{"record":{"id":"e1ac1007331e70b5","repo":"GoogleContainerTools/skaffold","slug":"could-not-fetch-deployments-w","errorCode":null,"errorMessage":"could not fetch deployments: %w","messagePattern":"could not fetch deployments: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/skaffold/kubernetes/status/status_check.go","lineNumber":348,"sourceCode":"\tfor _, r := range uRes {\n\t\tresName := r.GroupVersionKind().String()\n\t\tif r.GetName() != \"\" {\n\t\t\tresName = fmt.Sprintf(\"%s, Name=%s\", resName, r.GetName())\n\t\t}\n\t\tpd := diag.New([]string{ns}).\n\t\t\tWithValidators([]validator.Validator{validator.NewCustomValidator(client, dynClient, r.GroupVersionKind())})\n\t\tresult = append(result, resource.NewResource(resName, resource.ResourceTypes.CustomResource, ns, deadlineDuration, tolerateFailures).WithValidator(pd))\n\t}\n\n\treturn result, nil\n}\n\nfunc getDeployments(ctx context.Context, client kubernetes.Interface, ns string, l *label.DefaultLabeller, deadlineDuration time.Duration, tolerateFailures bool) ([]*resource.Resource, error) {\n\tdeps, err := client.AppsV1().Deployments(ns).List(ctx, metav1.ListOptions{\n\t\tLabelSelector: l.RunIDSelector(),\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not fetch deployments: %w\", err)\n\t}\n\n\tresources := make([]*resource.Resource, len(deps.Items))\n\tfor i, d := range deps.Items {\n\t\tvar deadline time.Duration\n\t\tif d.Spec.ProgressDeadlineSeconds == nil || *d.Spec.ProgressDeadlineSeconds == kubernetesMaxDeadline {\n\t\t\tdeadline = deadlineDuration\n\t\t} else {\n\t\t\tdeadline = time.Duration(*d.Spec.ProgressDeadlineSeconds) * time.Second\n\t\t}\n\n\t\tpd := diag.New([]string{d.Namespace}).\n\t\t\tWithLabel(label.RunIDLabel, l.Labels()[label.RunIDLabel]).\n\t\t\tWithValidators([]validator.Validator{validator.NewPodValidator(client, validator.NewDeploymentPodsSelector(client, d))})\n\n\t\tfor k, v := range d.Spec.Template.Labels {\n\t\t\tpd = pd.WithLabel(k, v)\n\t\t}","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/GoogleContainerTools/skaffold/blob/a1189de023efc32d4b8e11f395acc678aa555011/pkg/skaffold/kubernetes/status/status_check.go#L330-L366","documentation":"getDeployments wraps any error from listing Deployments (client.AppsV1().Deployments(ns).List with the run-id label selector) with 'could not fetch deployments'. statusCheck converts it to STATUSCHECK_DEPLOYMENT_FETCH_ERR. The wrapped cause is the raw Kubernetes client error (network, RBAC, timeout).","triggerScenarios":"Deployments List call fails for a namespace: connection refused/timeout to API server, 403 on list deployments.apps, nonexistent namespace, context pointing to wrong cluster, or context deadline exceeded before getDeadline.","commonSituations":"kubeconfig switched to a cluster without the deployed app; CI runner losing network to the control plane; RBAC roles missing deployments.apps; expired cloud credentials; namespace deleted mid-run.","solutions":["Reproduce the raw call: 'kubectl get deployments -n <ns> -l <run-id-selector>' and read the wrapped error","Fix connectivity/credentials: refresh kubeconfig (e.g. gcloud container clusters get-credentials) and re-authenticate","Fix RBAC if 403: grant get/list/watch on deployments.apps in the namespace","Verify the namespace exists and the context matches the deployed cluster","Increase statusCheck deadline or retry once the API server is responsive"],"exampleFix":"// before: stale CI kubeconfig pointing at old cluster\n//   kubectl config use-context old-cluster\n// after:\n//   gcloud container clusters get-credentials my-cluster --region us-central1\n//   kubectl config use-context my-cluster","handlingStrategy":"retry","validationCode":"const ctxOk = execSync('kubectl config current-context').toString().trim();\nconst nsOk = execSync(`kubectl get ns ${ns} --request-timeout=10s`).toString();\nconst canList = execSync(`kubectl auth can-i list deployments.apps -n ${ns}`).toString().trim();\nif (canList !== 'yes') throw new Error(`RBAC: cannot list deployments in ${ns} (ctx=${ctxOk})`);","typeGuard":"function isDeploymentFetchErr(err) {\n  return err != null && typeof err.message === 'string' && err.message.includes('could not fetch deployments');\n}","tryCatchPattern":"for (let attempt = 0; attempt < 3; attempt++) {\n  try { await statusCheck(); break; }\n  catch (err) {\n    if (isDeploymentFetchErr(err) && /timeout|connection refused|connection reset/i.test(err.message) && attempt < 2) {\n      await sleep(2000 * (attempt + 1));\n      continue;\n    }\n    throw err;\n  }\n}","preventionTips":["Refresh kubeconfig/credentials at the start of CI jobs","Grant deployments.apps get/list/watch in every status-checked namespace","Add deadline headroom via statusCheck.deadlineSeconds","Retry transient network errors with exponential backoff","Confirm the context matches the deployed cluster before status check"],"tags":["kubernetes","deployment","rbac","api-server","network"],"backgroundTag":"kubernetes-api-list-forbidden","analyzedSha":"a1189de023efc32d4b8e11f395acc678aa555011","analyzedAt":"2026-09-05T12:09:27.064Z","contentChangedAt":"2026-09-05T12:09:27.064Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}