{"record":{"id":"556f55f552f5fad0","repo":"GoogleContainerTools/skaffold","slug":"statuscheck-deployment-fetch-err","errorCode":"STATUSCHECK_DEPLOYMENT_FETCH_ERR","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":184,"sourceCode":"\nfunc (s *monitor) Reset() {\n\ts.seenResources.Reset()\n}\n\nfunc (s *monitor) statusCheck(ctx context.Context, out io.Writer) (proto.StatusCode, error) {\n\tclient, err := kubernetesclient.Client(s.kubeContext)\n\tif err != nil {\n\t\treturn proto.StatusCode_STATUSCHECK_KUBECTL_CLIENT_FETCH_ERR, fmt.Errorf(\"getting Kubernetes client: %w\", err)\n\t}\n\tdynClient, err := kubernetesclient.DynamicClient(s.kubeContext)\n\tif err != nil {\n\t\treturn proto.StatusCode_STATUSCHECK_KUBECTL_CLIENT_FETCH_ERR, fmt.Errorf(\"getting Kubernetes client: %w\", err)\n\t}\n\tresources := make([]*resource.Resource, 0)\n\tfor _, n := range *s.namespaces {\n\t\tnewDeployments, err := getDeployments(ctx, client, n, s.labeller, getDeadline(s.deadlineSeconds), s.tolerateFailures)\n\t\tif err != nil {\n\t\t\treturn proto.StatusCode_STATUSCHECK_DEPLOYMENT_FETCH_ERR, fmt.Errorf(\"could not fetch deployments: %w\", err)\n\t\t}\n\t\tfor _, d := range newDeployments {\n\t\t\tif s.seenResources.Contains(d) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tresources = append(resources, d)\n\t\t\ts.seenResources.Add(d)\n\t\t}\n\n\t\tnewStatefulSets, err := getStatefulSets(ctx, client, n, s.labeller, getDeadline(s.deadlineSeconds), s.tolerateFailures)\n\t\tif err != nil {\n\t\t\treturn proto.StatusCode_STATUSCHECK_STATEFULSET_FETCH_ERR, fmt.Errorf(\"could not fetch statefulsets: %w\", err)\n\t\t}\n\t\tfor _, d := range newStatefulSets {\n\t\t\tif s.seenResources.Contains(d) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tresources = append(resources, d)","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/GoogleContainerTools/skaffold/blob/a1189de023efc32d4b8e11f395acc678aa555011/pkg/skaffold/kubernetes/status/status_check.go#L166-L202","documentation":"Skaffold's status check wraps every error from listing Kubernetes Deployments in a namespace with this message before returning STATUSCHECK_DEPLOYMENT_FETCH_ERR. The underlying error comes from the typed client call client.AppsV1().Deployments(ns).List(...) (via getDeployments), so any API-server, RBAC, namespace, or network failure surfaces here.","triggerScenarios":"getDeployments fails on client.AppsV1().Deployments(ns).List with a label selector l.RunIDSelector(): API server unreachable, RBAC denies list deployments, namespace does not exist, context/cluster misconfigured, or network timeout before the deadline.","commonSituations":"Wrong kubectl context (pointing at a cluster where the run-id labeled deployments don't exist or access is denied); user lacks 'list deployments' in the namespace; namespace typo; VPN/proxy down; expired credentials (e.g. GKE token); API server briefly unavailable during deploy.","solutions":["Run 'kubectl auth can-i list deployments.apps -n <ns>' with the same kubeconfig to verify RBAC","Verify the cluster context and namespace: 'kubectl config current-context' and 'kubectl get ns <ns>'","Check connectivity to the API server: 'kubectl get deployments -n <ns>' directly","If RBAC is the issue, bind a ClusterRole with get/list/watch on deployments.apps to the user/service account","Re-run skaffold once the cluster/network is reachable — the status check is retryable"],"exampleFix":"// before: no RBAC for deployments\n//   kubectl create rolebinding dev --clusterrole=view --user=dev -n app  # view lacks nothing here, but custom roles often do\n// after: grant explicit deployment list access\n//   kubectl create clusterrole skaffold-status --verb=get,list,watch --resource=deployments.apps\n//   kubectl create rolebinding skaffold-status --clusterrole=skaffold-status --user=dev","handlingStrategy":"try-catch","validationCode":"kubectl auth can-i list deployments.apps -n <ns> # must print yes before running","typeGuard":"func IsDeploymentFetchErr(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"could not fetch deployments\")\n}","tryCatchPattern":"if err := runStatusCheck(ctx); err != nil {\n\tif IsDeploymentFetchErr(err) {\n\t\tvar se *apierrors.StatusError\n\t\tif errors.As(err, &se) && apierrors.IsForbidden(err) {\n\t\t\t// fix RBAC\n\t\t}\n\t\treturn fmt.Errorf(\"status check aborted: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Run kubectl auth can-i list deployments.apps for every status-check namespace in CI setup","Pin and verify kubectl context before deploy","Refresh cloud credentials before long-running pipelines","Validate namespaces in skaffold config exist before deploying"],"tags":["kubernetes","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"}