{"record":{"id":"0ea375a7d0e341ce","repo":"kubernetes/kops","slug":"error-watching-ingresses-v","errorCode":null,"errorMessage":"error watching ingresses: %v","messagePattern":"error watching ingresses: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"dns-controller/pkg/watchers/ingress.go","lineNumber":100,"sourceCode":"\t\t\tingress := &ingressList.Items[i]\n\t\t\tklog.V(4).Infof(\"found ingress: %v\", ingress.Name)\n\t\t\tkey := c.updateIngressRecords(ingress)\n\t\t\tfoundKeys[key] = true\n\t\t}\n\t\tfor _, key := range allKeys {\n\t\t\tif !foundKeys[key] {\n\t\t\t\t// The ingress previously existed, but no longer exists; delete it from the scope\n\t\t\t\tklog.V(2).Infof(\"removing ingress not found in list: %s\", key)\n\t\t\t\tc.scope.Replace(key, nil)\n\t\t\t}\n\t\t}\n\t\tc.scope.MarkReady()\n\n\t\tlistOpts.Watch = true\n\t\tlistOpts.ResourceVersion = ingressList.ResourceVersion\n\t\twatcher, err := c.client.NetworkingV1().Ingresses(c.namespace).Watch(ctx, listOpts)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"error watching ingresses: %v\", err)\n\t\t}\n\t\tch := watcher.ResultChan()\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-stopCh:\n\t\t\t\tklog.Infof(\"Got stop signal\")\n\t\t\t\treturn true, nil\n\t\t\tcase event, ok := <-ch:\n\t\t\t\tif !ok {\n\t\t\t\t\tklog.Infof(\"ingress watch channel closed\")\n\t\t\t\t\treturn false, nil\n\t\t\t\t}\n\n\t\t\t\tingress := event.Object.(*v1.Ingress)\n\t\t\t\tklog.V(4).Infof(\"ingress changed: %s %v\", event.Type, ingress.Name)\n\n\t\t\t\tswitch event.Type {\n\t\t\t\tcase watch.Added, watch.Modified:","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/dns-controller/pkg/watchers/ingress.go#L82-L118","documentation":"After an initial list, the ingress watcher establishes a Watch on ingresses (NetworkingV1().Ingresses(namespace).Watch) starting from the list's ResourceVersion; if the watch request fails the error is wrapped and the watcher signals the outer loop to retry. This is distinct from errors on the watch's result channel, which are handled in-loop.","triggerScenarios":"The Watch API call itself fails: RBAC lacks watch verb, ResourceVersion is stale/expired (410 Gone handling depends on the retry loop), API server connection drops at watch setup, or invalid ListOptions (e.g. bad ResourceVersion).","commonSituations":"ClusterRole granting list but not watch on ingresses; long-lived controller resuming after API server restart with a too-old ResourceVersion; network interruptions in flaky environments; API server rate limiting.","solutions":["Check the wrapped %v cause; Forbidden -> add watch verb to RBAC","Let the controller retry — the outer loop re-lists and re-watches with a fresh ResourceVersion","Ensure the dns-controller SA has list+watch on ingresses: verbs [\"list\",\"watch\",\"get\"]","Verify network stability / API server health if connection errors recur"],"exampleFix":"// before\nverbs: [\"list\"]\n// after\nverbs: [\"list\",\"watch\"]","handlingStrategy":"retry","validationCode":"// ensure watch permission before starting\nauthz := client.AuthorizationV1().SelfSubjectAccessReviews()\nsar, err := authz.Create(ctx, &authorizationv1.SelfSubjectAccessReview{\n    Spec: authorizationv1.SelfSubjectAccessReviewSpec{\n        ResourceAttributes: &authorizationv1.ResourceAttributes{\n            Group: \"networking.k8s.io\", Resource: \"ingresses\", Verb: \"watch\", Namespace: namespace}}})\nif err == nil && !sar.Status.Allowed { klog.Fatalf(\"SA lacks watch on ingresses in %s\", namespace) }","typeGuard":null,"tryCatchPattern":"ok, err := runOnce(ctx, c, listOpts)\nif err != nil {\n    if strings.Contains(err.Error(), \"error watching ingresses\") {\n        klog.Warningf(\"watch setup failed, will re-list and re-watch: %v\", err)\n        return false, nil // backoff, then fresh list sets a new ResourceVersion\n    }\n}","preventionTips":["Grant the watch verb alongside list in RBAC","Accept re-list on watch failure — stale ResourceVersions self-heal via the retry loop","Keep API server connections stable; avoid aggressive idle timeouts between controller and API"],"tags":["kubernetes","ingress","watch","rbac"],"backgroundTag":"kubernetes-api-watch-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}