Namespace label changes are not re-evaluated for allowedRoutes namespace selectors until controller restart
#9,625 opened on Jul 31, 2026
Repository metrics
- Stars
- (2,871 stars)
- PR merge metrics
- (PR metrics pending)
Description
Description
When a Gateway listener restricts route attachment with allowedRoutes.namespaces.from: Selector, changing a namespace's labels after an HTTPRoute in it has been evaluated does not trigger re-evaluation: the route stays NotAllowedByListeners indefinitely even though the namespace now matches the selector. Restarting the envoy-gateway controller — with no other change — immediately flips the route to Accepted, which points at stale namespace state in the controller rather than a configuration problem.
I hit this in a real cluster (tightening a Gateway from from: All to a label selector; namespaces labeled around the same time stayed rejected until a controller restart) and reproduced it minimally on a fresh kind cluster.
Environment
- Envoy Gateway v1.8.3 (release
install.yaml, unmodified) - kind, Kubernetes v1.36.1 (kindest/node)
Minimal reproduction
kind create cluster --name eg-repro --wait 120s
kubectl apply --server-side -f https://github.com/envoyproxy/gateway/releases/download/v1.8.3/install.yaml
kubectl -n envoy-gateway-system rollout status deployment envoy-gateway --timeout=180s
kubectl apply -f - <<'YAML'
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata: {name: eg}
spec: {controllerName: gateway.envoyproxy.io/gatewayclass-controller}
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata: {name: demo-gw, namespace: default}
spec:
gatewayClassName: eg
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels: {access: granted}
---
apiVersion: v1
kind: Namespace
metadata: {name: app}
YAML
kubectl apply -f - <<'YAML'
apiVersion: v1
kind: Service
metadata: {name: dummy, namespace: app}
spec: {ports: [{port: 80}]}
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata: {name: dummy, namespace: app}
spec:
parentRefs: [{name: demo-gw, namespace: default}]
rules: [{backendRefs: [{name: dummy, port: 80}]}]
YAML
sleep 30
kubectl -n app get httproute dummy -o jsonpath='{.status.parents[0].conditions[?(@.type=="Accepted")].reason}'
# -> NotAllowedByListeners (expected: namespace does not match yet)
kubectl label ns app access=granted
sleep 90
kubectl -n app get httproute dummy -o jsonpath='{.status.parents[0].conditions[?(@.type=="Accepted")].reason}'
# -> NotAllowedByListeners (BUG: namespace now matches the selector)
kubectl -n envoy-gateway-system rollout restart deployment envoy-gateway
kubectl -n envoy-gateway-system rollout status deployment envoy-gateway --timeout=120s
sleep 20
kubectl -n app get httproute dummy -o jsonpath='{.status.parents[0].conditions[?(@.type=="Accepted")].reason}'
# -> Accepted (nothing changed except the restart)
Expected behavior
Labeling the namespace to match the listener's selector should cause the HTTPRoute to become Accepted without a controller restart — the Gateway API spec expects implementations to respond to namespace label changes that affect allowedRoutes selection.
Workaround
kubectl -n envoy-gateway-system rollout restart deployment envoy-gateway after changing namespace labels that feed listener selectors.