kubernetes/kops · error

unknown scope for gvk %s: %q

Error message

unknown scope for gvk %s: %q

What it means

A fallback branch in dynamicResource: after namespace-scoped and root-scoped cases, any unrecognized RESTScopeName indicates the RESTMapper returned data the client does not understand. The code itself calls this panic-level, i.e. it should be unreachable with a correct discovery client and k8s.io/client-go version.

Source

Thrown at pkg/applylib/applyset/unstructuredclient.go:75

	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) {
	dynamicResource, err := c.dynamicResource(ctx, gvk, nn.Namespace)
	if err != nil {
		return nil, err
	}

	name := nn.Name
	patched, err := dynamicResource.Patch(ctx, name, patchType, data, opt)
	if err != nil {
		return nil, fmt.Errorf("error patching object: %w", err)
	}
	return patched, nil
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Check go.mod for mismatched k8s.io/client-go and apimachinery versions and run make gomod to realign vendoring
  2. Re-run discovery / rebuild the RESTMapper cache and retry
  3. If using a custom RESTMapper (e.g. in tests), ensure its mappings return meta.RESTScopeNamespace or meta.RESTScopeRoot
  4. Report upstream with the gvk and scope string if it reproduces with stock client-go
Defensive patterns

Strategy: try-catch

Validate before calling

mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err == nil {
	scope := mapping.Scope.Name()
	if scope != meta.RESTScopeNameNamespace && scope != meta.RESTScopeNameRoot {
		return fmt.Errorf("unexpected REST scope %q for %s; check client-go versions", scope, gvk)
	}
}

Type guard

func knownScope(mapping *meta.RESTMapping) bool {
	name := mapping.Scope.Name()
	return name == meta.RESTScopeNameNamespace || name == meta.RESTScopeNameRoot
}

Try / catch

res, err := client.Get(ctx, gvk, nn)
if err != nil {
	if strings.HasPrefix(err.Error(), "unknown scope for gvk") {
		// dependency/invariant bug: rebuild discovery cache, realign client-go
		return fmt.Errorf("internal: bad REST mapping for %s: %w", gvk, err)
	}
	return err
}

Prevention

When it happens

Trigger: Only reachable if restMapping.Scope.Name() returns a value other than "namespace" or "" (root), which implies a corrupted/mis-built RESTMapping or an unexpected client-go version change.

Common situations: Practically never hit in production; may appear when vendoring mismatched versions of k8s.io/client-go / discovery, or with custom/simulated RESTMappers in tests returning fake scopes.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/ffb2449036be6511. Report an issue: GitHub.