kubernetes/kops · error

Forbidden: namespace does not match

Error message

Forbidden: namespace does not match

What it means

handleCreateDiscoveryEndpoint validates that the namespace in the request body's ObjectMeta matches the {namespace} path segment. A mismatch (including an empty or missing body namespace) is rejected with 403 'Forbidden: namespace does not match'. Note the body namespace must be set exactly, since an empty body namespace will not equal the URL namespace.

Source

Thrown at discovery/pkg/discovery/server.go:168

func (s *Server) handleCreateDiscoveryEndpoint(w http.ResponseWriter, r *http.Request, userInfo *UserInfo) {
	universeID := r.PathValue("universe")
	ns := r.PathValue("namespace")

	var input api.DiscoveryEndpoint
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		http.Error(w, "Invalid request body", http.StatusBadRequest)
		return
	}

	// Validation: ensure the name matches the clientID from the cert
	if input.ObjectMeta.Name != "" && input.ObjectMeta.Name != userInfo.ClientID {
		http.Error(w, fmt.Sprintf("Forbidden: cannot register node name '%s' with client cert '%s'", input.ObjectMeta.Name, userInfo.ClientID), http.StatusForbidden)
		return
	}

	// Validation: ensure the namespace in body matches the URL
	if input.ObjectMeta.Namespace != ns {
		http.Error(w, "Forbidden: namespace does not match", http.StatusForbidden)
		return
	}

	if err := s.Store.UpsertDiscoveryEndpoint(r.Context(), universeID, &input); err != nil {
		http.Error(w, fmt.Sprintf("Error creating endpoint: %v", err), http.StatusInternalServerError)
		return
	}

	// Return the created object
	s.writeJSON(w, http.StatusCreated, input)
}

func (s *Server) handleApplyDiscoveryEndpoint(w http.ResponseWriter, r *http.Request, userInfo *UserInfo) {
	ctx := r.Context()
	log := klog.FromContext(ctx)

	universeID := r.PathValue("universe")
	ns := r.PathValue("namespace")

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Set metadata.namespace in the body to exactly the namespace in the URL path.
  2. Fix the URL to use the namespace the object belongs in.
  3. Ensure your manifest template populates metadata.namespace.
  4. Client-side check: if body.Namespace != ns, fix before sending.

Example fix

// before
body := []byte(`{"metadata":{"name":"node1"}}`) // namespace missing
// after
body := []byte(`{"metadata":{"name":"node1","namespace":"default"}}`)
Defensive patterns

Strategy: validation

Validate before calling

if body.Namespace != urlNamespace {
    return fmt.Errorf("body namespace %q != URL namespace %q", body.Namespace, urlNamespace)
}

Prevention

When it happens

Trigger: POST to .../namespaces/{ns}/discoveryendpoints where the JSON body's metadata.namespace is different, empty, or omitted; client templated the manifest for another namespace.

Common situations: Applying a manifest generated for namespace 'kube-system' against a 'default' namespace URL; forgetting metadata.namespace entirely in the payload; copy-pasted manifests.

Understand the failure class

Related errors


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