{"record":{"id":"d7c1e6e8fb018e98","repo":"kubernetes/kops","slug":"forbidden-name-does-not-match","errorCode":null,"errorMessage":"Forbidden: name does not match","messagePattern":"Forbidden: name does not match","errorType":"http","errorClass":null,"httpStatus":403,"severity":"error","filePath":"discovery/pkg/discovery/server.go","lineNumber":206,"sourceCode":"\n\tvar input api.DiscoveryEndpoint\n\tif err := json.NewDecoder(r.Body).Decode(&input); err != nil {\n\t\tlog.Info(\"invalid request body\", \"error\", err)\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\tlog.Info(\"Forbidden: cannot register node name\", \"name\", input.ObjectMeta.Name, \"clientID\", 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 name in body matches the URL\n\tif input.ObjectMeta.Name != name {\n\t\tlog.Info(\"Forbidden: name does not match\", \"name\", input.ObjectMeta.Name, \"expected\", name)\n\t\thttp.Error(w, \"Forbidden: name does not match\", 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\tlog.Info(\"Forbidden: namespace does not match\", \"namespace\", input.ObjectMeta.Namespace, \"expected\", 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\tlog.Error(err, \"error applying endpoint\")\n\t\thttp.Error(w, fmt.Sprintf(\"Error applying endpoint: %v\", err), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// Return the created object\n\ts.writeJSON(w, http.StatusCreated, input)","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/discovery/pkg/discovery/server.go#L188-L224","documentation":"The apply endpoint requires that the metadata.name in the request body equals the {name} path parameter. If they differ, the server returns HTTP 403 rather than silently renaming or creating a duplicate object. This keeps apply semantics unambiguous: the URL identifies exactly the object being written.","triggerScenarios":"Apply (POST/PUT) to .../discoveryendpoints/{name} where the decoded DiscoveryEndpoint body has metadata.name different from the {name} in the URL path (including empty body name while the URL name is non-empty).","commonSituations":"Client builds the URL from one variable and the body from a stale/renamed value; kubectl-style apply where the manifest name was edited but the URL is derived from the old resource name; hand-rolled HTTP clients that forget to sync path and body.","solutions":["Make metadata.name in the request body identical to the {name} segment of the request URL","Fix client templating so URL and body derive the name from the same source value","If a rename is intended, apply to the new-name URL (and delete the old object); this endpoint never renames"],"exampleFix":"// before\nname := \"node-a\"\nurl := base + \"/discoveryendpoints/\" + name\nbody := DiscoveryEndpoint{ObjectMeta: metav1.ObjectMeta{Name: \"node-b\"}}\n// after\nname := \"node-a\"\nurl := base + \"/discoveryendpoints/\" + name\nbody := DiscoveryEndpoint{ObjectMeta: metav1.ObjectMeta{Name: name}}","handlingStrategy":"validation","validationCode":"// Go client: body name must equal the URL name before applying\nfunc validateNameMatch(ep *DiscoveryEndpoint, urlName string) error {\n    if ep.ObjectMeta.Name != urlName {\n        return fmt.Errorf(\"metadata.name %q != URL name %q\", ep.ObjectMeta.Name, urlName)\n    }\n    return nil\n}","typeGuard":"func nameMatchesPath(ep *DiscoveryEndpoint, urlName string) bool {\n    return ep.ObjectMeta.Name == urlName\n}","tryCatchPattern":"resp, err := client.ApplyDiscoveryEndpoint(ctx, universe, ns, name, ep)\nif err != nil {\n    var httpErr *HTTPError\n    if errors.As(err, &httpErr) && httpErr.StatusCode == http.StatusForbidden && httpErr.Body == \"Forbidden: name does not match\" {\n        // set ep.ObjectMeta.Name = name (the URL value) and retry once\n    }\n    return err\n}","preventionTips":["Build the URL and the body from a single name variable","Add a client-side assertion that body.metadata.name equals the path name before every apply","For renames, apply to the new-name URL (this endpoint never renames objects)","Cover the client apply helper with a unit test asserting URL/body consistency"],"tags":["http","forbidden","validation","discovery"],"backgroundTag":"request-name-path-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"}