kubernetes/kops · error
namespace was not provided for namespace-scoped object %v
Error message
namespace was not provided for namespace-scoped object %v
What it means
This error comes from the dynamicResource helper in kOps' applyset UnstructuredClient. Before creating a dynamic (unstructured) resource client, it resolves the GVK's REST scope via a discovery RESTMapper. If the object's kind is namespace-scoped but no namespace was supplied in the NamespacedName, it cannot build a valid client and returns this error instead of a confusing server-side 404/400.
Source
Thrown at pkg/applylib/applyset/unstructuredclient.go:62
restMapper: options.RESTMapper,
}
}
// dynamicResource is a helper to get the resource for a gvk (with the namespace)
// It returns an error if a namespace is provided for a cluster-scoped resource,
// or no namespace is provided for a namespace-scoped resource.
func (c *UnstructuredClient) dynamicResource(ctx context.Context, gvk schema.GroupVersionKind, ns string) (dynamic.ResourceInterface, error) {
restMapping, err := c.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil {
return nil, fmt.Errorf("error getting rest mapping for %v: %w", gvk, err)
}
gvr := restMapping.Resource
switch restMapping.Scope.Name() {
case meta.RESTScopeNameNamespace:
if ns == "" {
// TODO: Differentiate between server-fixable vs client-fixable errors?
return nil, fmt.Errorf("namespace was not provided for namespace-scoped object %v", gvk)
}
return c.client.Resource(gvr).Namespace(ns), nil
case meta.RESTScopeNameRoot:
if ns != "" {
// TODO: Differentiate between server-fixable vs client-fixable errors?
return nil, fmt.Errorf("namespace %q was provided for cluster-scoped object %v", ns, gvk)
}
return c.client.Resource(gvr), nil
default:
// Internal error ... this is panic-level
return nil, fmt.Errorf("unknown scope for gvk %s: %q", gvk, restMapping.Scope.Name())
}
}
// Patch performs a Patch operation, used for server-side apply and client-side patch.
func (c *UnstructuredClient) Patch(ctx context.Context, gvk schema.GroupVersionKind, nn types.NamespacedName, patchType types.PatchType, data []byte, opt metav1.PatchOptions) (*unstructured.Unstructured, error) {View on GitHub (pinned to 4c8573c808)
Solutions
- Set nn.Namespace to the target namespace before calling Patch/Update/Get
- Read the namespace from the object metadata: obj.GetNamespace(), and default it explicitly if empty
- Verify the kind really is namespace-scoped (some kinds like ClusterRole look similar to namespaced Role) and that your namespace defaulting logic runs
- If the namespace should come from a flag/config, propagate it into every NamespacedName built by your code
Example fix
// before
nn := types.NamespacedName{Name: "my-deploy"}
client.Get(ctx, gvk, nn)
// after
nn := types.NamespacedName{Name: "my-deploy", Namespace: "kube-system"}
client.Get(ctx, gvk, nn) Defensive patterns
Strategy: validation
Validate before calling
func ensureNamespace(gvk schema.GroupVersionKind, nn types.NamespacedName) error {
switch gvk.Group + "/" + gvk.Kind {
case "apps/Deployment", "v1/Service", "v1/Secret", "v1/ConfigMap", "v1/Pod":
if nn.Namespace == "" {
return fmt.Errorf("kind %s requires a namespace; got empty", gvk.Kind)
}
}
return nil
} Type guard
func hasNamespace(nn types.NamespacedName) bool {
return nn.Namespace != ""
} Try / catch
obj, err := client.Get(ctx, gvk, nn)
if err != nil {
if strings.Contains(err.Error(), "namespace was not provided") {
return fmt.Errorf("programming error: set nn.Namespace for %s", gvk)
}
return err
} Prevention
- Always construct NamespacedName from obj.GetNamespace() rather than a fresh struct
- Default namespaces explicitly at manifest parse time, not at API-call time
- Use the RESTMapper to check scope before building the client
- Add unit tests asserting namespace is set for all namespaced kinds
When it happens
Trigger: Calling Patch, Update, or Get on the UnstructuredClient with a gvk that the RESTMapper maps to RESTScopeNameNamespace while passing types.NamespacedName with an empty Namespace field.
Common situations: Building or passing objects like Deployment, Service, or Secret without setting metadata.namespace (e.g. parsed from YAML that omits the namespace field); constructing NamespacedName from an object before defaulting; apply-set tooling reading objects from manifests with no namespace.
Related errors
- error querying namespace %q: %v
- failed to parse apiVersion %q
- failed to find kind in object
- error listing objects in namespace %s: %w
- invalid InstanceGroup name: %v
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/4e93e365705d0bb4.
Report an issue: GitHub.