{"record":{"id":"984d820190b2ccec","repo":"kubernetes/kops","slug":"namespace-q-was-provided-for-cluster-scoped-objec","errorCode":null,"errorMessage":"namespace %q was provided for cluster-scoped object %v","messagePattern":"namespace %q was provided for cluster-scoped object (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/applylib/applyset/unstructuredclient.go","lineNumber":69,"sourceCode":"func (c *UnstructuredClient) dynamicResource(ctx context.Context, gvk schema.GroupVersionKind, ns string) (dynamic.ResourceInterface, error) {\n\trestMapping, err := c.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting rest mapping for %v: %w\", gvk, err)\n\t}\n\tgvr := restMapping.Resource\n\n\tswitch restMapping.Scope.Name() {\n\tcase meta.RESTScopeNameNamespace:\n\t\tif ns == \"\" {\n\t\t\t// TODO: Differentiate between server-fixable vs client-fixable errors?\n\t\t\treturn nil, fmt.Errorf(\"namespace was not provided for namespace-scoped object %v\", gvk)\n\t\t}\n\t\treturn c.client.Resource(gvr).Namespace(ns), nil\n\n\tcase meta.RESTScopeNameRoot:\n\t\tif ns != \"\" {\n\t\t\t// TODO: Differentiate between server-fixable vs client-fixable errors?\n\t\t\treturn nil, fmt.Errorf(\"namespace %q was provided for cluster-scoped object %v\", ns, gvk)\n\t\t}\n\t\treturn c.client.Resource(gvr), nil\n\n\tdefault:\n\t\t// Internal error ... this is panic-level\n\t\treturn nil, fmt.Errorf(\"unknown scope for gvk %s: %q\", gvk, restMapping.Scope.Name())\n\t}\n}\n\n// Patch performs a Patch operation, used for server-side apply and client-side patch.\nfunc (c *UnstructuredClient) Patch(ctx context.Context, gvk schema.GroupVersionKind, nn types.NamespacedName, patchType types.PatchType, data []byte, opt metav1.PatchOptions) (*unstructured.Unstructured, error) {\n\tdynamicResource, err := c.dynamicResource(ctx, gvk, nn.Namespace)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tname := nn.Name\n\tpatched, err := dynamicResource.Patch(ctx, name, patchType, data, opt)","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/applylib/applyset/unstructuredclient.go#L51-L87","documentation":"The mirror image of the missing-namespace check: when the RESTMapper reports the GVK as cluster-scoped (root scope, e.g. ClusterRole, Namespace, CRD), passing a namespace is contradictory and the client refuses to build a namespaced dynamic client. This prevents silently applying a namespace filter that the API server would reject.","triggerScenarios":"Calling Patch, Update, or Get with a cluster-scoped gvk while nn.Namespace is non-empty, e.g. getting a Namespace or ClusterRole with Namespace set to \"default\".","commonSituations":"Generic apply logic that always fills in a default namespace for every object; copying a namespace from a parent context onto all objects; YAML lists where cluster-scoped add-ons inherit a namespace from surrounding code.","solutions":["Leave nn.Namespace empty (\"\") for cluster-scoped kinds","Detect scope via the RESTMapper (or a known-kind list) before building NamespacedName and clear the namespace for root-scoped objects","Audit defaulting code that blindly assigns a namespace to every object in an apply set"],"exampleFix":"// before\nnn := types.NamespacedName{Name: \"cluster-admin\", Namespace: \"default\"}\n// ClusterRole is cluster-scoped\nclient.Get(ctx, clusterRoleGVK, nn)\n// after\nnn := types.NamespacedName{Name: \"cluster-admin\"}\nclient.Get(ctx, clusterRoleGVK, nn)","handlingStrategy":"validation","validationCode":"clusterScopedKinds := map[string]bool{\"Namespace\": true, \"Node\": true, \"ClusterRole\": true, \"CustomResourceDefinition\": true, \"PersistentVolume\": true}\nif clusterScopedKinds[gvk.Kind] && nn.Namespace != \"\" {\n\treturn fmt.Errorf(\"kind %s is cluster-scoped; clear nn.Namespace\", gvk.Kind)\n}","typeGuard":"func isClusterScopedCall(gvk schema.GroupVersionKind, nn types.NamespacedName) bool {\n\treturn nn.Namespace != \"\" && clusterScopedKinds[gvk.Kind]\n}","tryCatchPattern":"obj, err := client.Get(ctx, gvk, nn)\nif err != nil {\n\tif strings.Contains(err.Error(), \"was provided for cluster-scoped object\") {\n\t\treturn client.Get(ctx, gvk, types.NamespacedName{Name: nn.Name})\n\t}\n\treturn err\n}","preventionTips":["Never blanket-default namespaces across a whole apply set; resolve scope per kind","Keep a known cluster-scoped kind list or query the RESTMapper","When copying namespaces from parent context, exclude root-scoped objects","Review generated manifests for stray namespace fields on cluster-scoped kinds"],"tags":["kubernetes","namespace","cluster-scoped"],"backgroundTag":"namespace-set-on-cluster-scoped-resource","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"}