{"record":{"id":"17d74b0293a9ca24","repo":"GoogleContainerTools/skaffold","slug":"patching-resource-q-w","errorCode":null,"errorMessage":"patching resource %q: %w","messagePattern":"patching resource %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/skaffold/deploy/label/labels.go","lineNumber":126,"sourceCode":"\t\tif accessor.GetNamespace() != \"\" {\n\t\t\tnamespace = accessor.GetNamespace()\n\t\t} else {\n\t\t\tnamespace = res.Namespace\n\t\t}\n\n\t\tns, err := resolveNamespace(namespace, kubeContext)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"resolving namespace: %w\", err)\n\t\t}\n\n\t\tlog.Entry(ctx).Debug(\"Patching\", name, \"in namespace\", ns)\n\t\tif _, err := client.Resource(gvr).Namespace(ns).Patch(ctx, name, types.StrategicMergePatchType, p, metav1.PatchOptions{}); err != nil {\n\t\t\treturn fmt.Errorf(\"patching resource %s/%q: %w\", ns, name, err)\n\t\t}\n\t} else {\n\t\tlog.Entry(ctx).Debug(\"Patching\", name)\n\t\tif _, err := client.Resource(gvr).Patch(ctx, name, types.StrategicMergePatchType, p, metav1.PatchOptions{}); err != nil {\n\t\t\treturn fmt.Errorf(\"patching resource %q: %w\", name, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc resolveNamespace(ns, kubeContext string) (string, error) {\n\tif ns != \"\" {\n\t\treturn ns, nil\n\t}\n\tcfg, err := kubectx.CurrentConfig()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"getting kubeconfig: %w\", err)\n\t}\n\n\tcurrent, present := cfg.Contexts[kubeContext]\n\tif present && current.Namespace != \"\" {\n\t\treturn current.Namespace, nil","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/GoogleContainerTools/skaffold/blob/a1189de023efc32d4b8e11f395acc678aa555011/pkg/skaffold/deploy/label/labels.go#L108-L144","documentation":"The cluster-scoped (non-namespaced) branch of updateRuntimeObject patches the resource via Resource(gvr).Patch without a namespace. This error wraps API server rejections or transport failures for that cluster-scoped patch — e.g. Nodes, ClusterRoles, or CRDs being labeled.","triggerScenarios":"Patching a cluster-scoped object fails: RBAC denies patch on cluster-scoped resources, object not found, conflict, or API server/network error.","commonSituations":"CI ServiceAccount without cluster-level patch rights; user lacks cluster-admin for the resource kind; resource removed concurrently; ephemeral cluster connectivity issues.","solutions":["Check `kubectl auth can-i patch <cluster-scoped-resource>` and grant a ClusterRole with patch if denied","Confirm the object exists: `kubectl get <resource> <name>`","Check connectivity with `kubectl cluster-info` and retry if transient","Ensure the manifest's apiVersion matches a served cluster-scoped resource"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"allowed, err := authClient.SelfSubjectAccessReviews().Create(ctx,\n    &authv1.SelfSubjectAccessReview{Spec: authv1.SelfSubjectAccessReviewSpec{\n        ResourceAttributes: &authv1.ResourceAttributes{Verb: \"patch\", Resource: resource}}}])","typeGuard":null,"tryCatchPattern":"if _, err := client.Resource(gvr).Patch(ctx, name, types.StrategicMergePatchType, p, metav1.PatchOptions{}); err != nil {\n    if apierrors.IsNotFound(err) { return nil }\n    if apierrors.IsForbidden(err) { return fmt.Errorf(\"needs cluster-level patch rights on %s: %w\", gvr.Resource, err) }\n    return retryable(err)\n}","preventionTips":["Bind ClusterRole with patch for cluster-scoped resources in CI","Verify objects exist with kubectl get before labeling","Retry transient network errors with backoff","Confirm apiVersion matches a served cluster-scoped resource"],"tags":["kubernetes","patch","rbac","cluster-scoped"],"backgroundTag":"kubernetes-patch-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"}