{"record":{"id":"026286d9c00c98ff","repo":"kubernetes/kops","slug":"error-listing-services-v","errorCode":null,"errorMessage":"error listing services: %v","messagePattern":"error listing services: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"dns-controller/pkg/watchers/service.go","lineNumber":79,"sourceCode":"\n\tstopCh := c.StopChannel()\n\tgo c.runWatcher(stopCh)\n\n\t<-stopCh\n\tklog.Infof(\"shutting down service controller\")\n}\n\nfunc (c *ServiceController) runWatcher(stopCh <-chan struct{}) {\n\trunOnce := func() (bool, error) {\n\t\tctx := context.TODO()\n\n\t\tvar listOpts metav1.ListOptions\n\t\tklog.V(4).Infof(\"querying without label filter\")\n\n\t\tallKeys := c.scope.AllKeys()\n\t\tserviceList, err := c.client.CoreV1().Services(c.namespace).List(ctx, listOpts)\n\t\tif err != nil {\n\t\t\treturn false, fmt.Errorf(\"error listing services: %v\", err)\n\t\t}\n\t\tfoundKeys := make(map[string]bool)\n\t\tfor i := range serviceList.Items {\n\t\t\tservice := &serviceList.Items[i]\n\t\t\tklog.V(4).Infof(\"found service: %v\", service.Name)\n\t\t\tkey := c.updateServiceRecords(service)\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 service previously existed, but no longer exists; delete it from the scope\n\t\t\t\tklog.V(2).Infof(\"removing service 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","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/dns-controller/pkg/watchers/service.go#L61-L97","documentation":"serviceController.runUpdater wraps failures from client.CoreV1().Services(c.namespace).List(ctx, listOpts) as \"error listing services: %v\". Services are listed to build/refresh DNS records (e.g. for LoadBalancer services); a failed list aborts the sync and it is retried. The wrapped client-go error names the real cause.","triggerScenarios":"client.CoreV1().Services(c.namespace).List(ctx, listOpts) errors: RBAC 403 on services list, invalid/nonexistent namespace, apiserver unreachable, or context timeout.","commonSituations":"Namespace-scoped ServiceAccount missing service list permissions; typo'd --watch-namespace; apiserver connectivity loss during control-plane upgrades.","solutions":["Grant 'list'/'get' on services to the controller's ServiceAccount in the target namespace.","Confirm the --watch-namespace exists; an empty namespace watches all.","Decode the wrapped error after '%v' (403 vs timeout) and act accordingly.","Ignore one-off transient failures; the controller retries automatically."],"exampleFix":"// before\nrules:\n- apiGroups: [\"\"]\n  resources: [\"pods\"]\n  verbs: [\"list\",\"watch\"]\n// after\nrules:\n- apiGroups: [\"\"]\n  resources: [\"pods\",\"services\"]\n  verbs: [\"list\",\"watch\"]","handlingStrategy":"try-catch","validationCode":"// Go: preflight service list in the target namespace\nif _, err := client.CoreV1().Services(ns).List(ctx, metav1.ListOptions{Limit: 1}); err != nil {\n    return fmt.Errorf(\"preflight service list failed: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"serviceList, err := client.CoreV1().Services(c.namespace).List(ctx, listOpts)\nif err != nil {\n    klog.Errorf(\"service list failed in ns %q: %v\", c.namespace, err)\n    time.Sleep(backoff)\n    return false, nil\n}","preventionTips":["Grant services list/get RBAC for the controller identity.","Validate --watch-namespace spelling and existence.","Run 'kubectl auth can-i list services' as the controller's ServiceAccount in CI."],"tags":["kubernetes","dns-controller","rbac","services"],"backgroundTag":"kubernetes-api-list-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"}