{"record":{"id":"d50b209257752c8d","repo":"kubernetes/kops","slug":"forbidden-namespace-does-not-match","errorCode":null,"errorMessage":"Forbidden: namespace does not match","messagePattern":"Forbidden: namespace does not match","errorType":"http","errorClass":null,"httpStatus":403,"severity":"error","filePath":"discovery/pkg/discovery/server.go","lineNumber":168,"sourceCode":"func (s *Server) handleCreateDiscoveryEndpoint(w http.ResponseWriter, r *http.Request, userInfo *UserInfo) {\n\tuniverseID := r.PathValue(\"universe\")\n\tns := r.PathValue(\"namespace\")\n\n\tvar input api.DiscoveryEndpoint\n\tif err := json.NewDecoder(r.Body).Decode(&input); err != nil {\n\t\thttp.Error(w, \"Invalid request body\", http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t// Validation: ensure the name matches the clientID from the cert\n\tif input.ObjectMeta.Name != \"\" && input.ObjectMeta.Name != userInfo.ClientID {\n\t\thttp.Error(w, fmt.Sprintf(\"Forbidden: cannot register node name '%s' with client cert '%s'\", input.ObjectMeta.Name, userInfo.ClientID), http.StatusForbidden)\n\t\treturn\n\t}\n\n\t// Validation: ensure the namespace in body matches the URL\n\tif input.ObjectMeta.Namespace != ns {\n\t\thttp.Error(w, \"Forbidden: namespace does not match\", http.StatusForbidden)\n\t\treturn\n\t}\n\n\tif err := s.Store.UpsertDiscoveryEndpoint(r.Context(), universeID, &input); err != nil {\n\t\thttp.Error(w, fmt.Sprintf(\"Error creating endpoint: %v\", err), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// Return the created object\n\ts.writeJSON(w, http.StatusCreated, input)\n}\n\nfunc (s *Server) handleApplyDiscoveryEndpoint(w http.ResponseWriter, r *http.Request, userInfo *UserInfo) {\n\tctx := r.Context()\n\tlog := klog.FromContext(ctx)\n\n\tuniverseID := r.PathValue(\"universe\")\n\tns := r.PathValue(\"namespace\")","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/discovery/pkg/discovery/server.go#L150-L186","documentation":"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.","triggerScenarios":"POST to .../namespaces/{ns}/discoveryendpoints where the JSON body's metadata.namespace is different, empty, or omitted; client templated the manifest for another namespace.","commonSituations":"Applying a manifest generated for namespace 'kube-system' against a 'default' namespace URL; forgetting metadata.namespace entirely in the payload; copy-pasted manifests.","solutions":["Set metadata.namespace in the body to exactly the namespace in the URL path.","Fix the URL to use the namespace the object belongs in.","Ensure your manifest template populates metadata.namespace.","Client-side check: if body.Namespace != ns, fix before sending."],"exampleFix":"// before\nbody := []byte(`{\"metadata\":{\"name\":\"node1\"}}`) // namespace missing\n// after\nbody := []byte(`{\"metadata\":{\"name\":\"node1\",\"namespace\":\"default\"}}`)","handlingStrategy":"validation","validationCode":"if body.Namespace != urlNamespace {\n    return fmt.Errorf(\"body namespace %q != URL namespace %q\", body.Namespace, urlNamespace)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set metadata.namespace explicitly in the payload","Derive body namespace from the same variable used to build the URL","Add a client-side pre-send assertion comparing body vs URL namespace"],"tags":["http","validation","forbidden","namespace"],"backgroundTag":"namespace-mismatch","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"}