{"record":{"id":"51afe93d10984db4","repo":"kubernetes/kops","slug":"error-watching-pods-v","errorCode":null,"errorMessage":"error watching pods: %v","messagePattern":"error watching pods: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"dns-controller/pkg/watchers/pod.go","lineNumber":102,"sourceCode":"\t\t\tpod := &podList.Items[i]\n\t\t\tklog.V(4).Infof(\"found pod: %v\", pod.Name)\n\t\t\tkey := c.updatePodRecords(pod)\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 pod previous existed, but no longer exists; delete it from the scope\n\t\t\t\tklog.V(2).Infof(\"removing pod 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 = podList.ResourceVersion\n\t\twatcher, err := c.client.CoreV1().Pods(c.namespace).Watch(ctx, listOpts)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"error watching pods: %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(\"pod watch channel closed\")\n\t\t\t\t\treturn false, nil\n\t\t\t\t}\n\n\t\t\t\tpod := event.Object.(*v1.Pod)\n\t\t\t\tklog.V(4).Infof(\"pod changed: %s %v\", event.Type, pod.Name)\n\n\t\t\t\tswitch event.Type {\n\t\t\t\tcase watch.Added, watch.Modified:","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/dns-controller/pkg/watchers/pod.go#L84-L120","documentation":"podController.runUpdater wraps failures from client.CoreV1().Pods(c.namespace).Watch(ctx, listOpts) as \"error watching pods: %v\". After listing pods, the controller opens a watch at podList.ResourceVersion for incremental updates; failure to establish the watch aborts the current sync (retried later). The cause is in the wrapped client-go error.","triggerScenarios":"client.CoreV1().Pods(c.namespace).Watch(ctx, listOpts) fails: ResourceVersion compacted/expired (410 Gone), RBAC lacking 'watch' on pods, namespace deleted mid-sync, ctx cancelled, or network interruption.","commonSituations":"etcd compaction invalidating the list's ResourceVersion; namespace removed while the controller watched it; missing watch permission in namespace-scoped RBAC; apiserver restarts.","solutions":["Ensure RBAC includes the 'watch' verb on pods in the target namespace.","For 'too old resource version' errors, allow the retry loop to re-list for a fresh ResourceVersion.","Recreate/verify the watched namespace if it was deleted.","Fix persistent connectivity problems between the controller and apiserver."],"exampleFix":"// before\nresources: [\"pods\"]\nverbs: [\"list\"]\n// after\nresources: [\"pods\"]\nverbs: [\"list\",\"watch\"]","handlingStrategy":"retry","validationCode":"// Go: check watch RBAC on pods via SelfSubjectAccessReview before starting\nspec.ResourceAttributes = &authorizationv1.ResourceAttributes{Verb: \"watch\", Resource: \"pods\", Namespace: ns}","typeGuard":null,"tryCatchPattern":"watcher, err := client.CoreV1().Pods(c.namespace).Watch(ctx, listOpts)\nif err != nil {\n    if apierrors.IsResourceExpired(err) || apierrors.IsGone(err) {\n        return false, nil // re-list to obtain fresh ResourceVersion\n    }\n    return false, fmt.Errorf(\"error watching pods: %v\", err)\n}","preventionTips":["Include 'watch' in RBAC alongside 'list' for pods.","Handle namespace deletion: recreate namespace or restart controller.","Treat 410 Gone as a normal re-list trigger, not a fatal fault."],"tags":["kubernetes","dns-controller","watch","pods"],"backgroundTag":"kubernetes-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"}