{"record":{"id":"2cfce035149a1ab4","repo":"ory/hydra","slug":"patch-includes-denied-path-s","errorCode":null,"errorMessage":"patch includes denied path: %s","messagePattern":"patch includes denied path: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"oryx/jsonx/patch.go","lineNumber":72,"sourceCode":"\t}\n\n\tdenyPattern := fmt.Sprintf(\"{%s}\", strings.ToLower(strings.Join(denyPaths, \",\")))\n\tmatcher, err := glob.Compile(denyPattern, '/')\n\tif err != nil {\n\t\treturn result, errors.WithStack(err)\n\t}\n\n\tfor _, op := range patch {\n\t\t// Some operations are buggy, see https://github.com/evanphx/json-patch/pull/158\n\t\tif isUnsupported(op) {\n\t\t\treturn result, errors.Errorf(\"unsupported operation: %s\", op.Kind())\n\t\t}\n\t\tpath, err := op.Path()\n\t\tif err != nil {\n\t\t\treturn result, errors.Errorf(\"error parsing patch operations: %v\", err)\n\t\t}\n\t\tif matcher.Match(strings.ToLower(path)) {\n\t\t\treturn result, errors.Errorf(\"patch includes denied path: %s\", path)\n\t\t}\n\n\t\t// JSON patch officially rejects replacing paths that don't exist, but we want to be more tolerant.\n\t\t// Therefore, we will ensure that all paths that we want to replace exist in the original document.\n\t\tif op.Kind() == \"replace\" && !isElementAccess(path) {\n\t\t\top[\"op\"] = new(json.RawMessage(`\"add\"`))\n\t\t}\n\t}\n\n\toriginal, err := json.Marshal(object)\n\tif err != nil {\n\t\treturn result, errors.WithStack(err)\n\t}\n\n\toptions := jsonpatch.NewApplyOptions()\n\toptions.EnsurePathExistsOnAdd = true\n\n\tmodified, err := patch.ApplyWithOptions(original, options)","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/oryx/jsonx/patch.go#L54-L90","documentation":"ApplyJSONPatch accepts denyPaths globs (compiled with gobwas/glob) and rejects any patch operation whose target path matches a denied pattern. This lets API surfaces (like patchOAuth2Client) protect immutable fields from modification. The error reports the offending path verbatim.","triggerScenarios":"Calling ApplyJSONPatch (oryx/jsonx/patch.go:72) with a patch operation whose \"path\" matches one of the denyPaths globs passed by the caller (e.g., attempting to PATCH a protected OAuth2 client field).","commonSituations":"Trying to modify read-only or server-managed fields through a PATCH endpoint — e.g., changing an OAuth2 client's token endpoint auth method, credentials, or other denied properties.","solutions":["Remove the denied field(s) from the patch and only patch allowed paths.","If the field must change, use the dedicated API for that change (e.g., replace the whole resource with PUT, or a specific endpoint for credentials).","Check the endpoint's documented denied paths and validate your patch paths against the same globs client-side before sending.","Verify glob case sensitivity: matching is done on the lowercased path, so pattern expectations should be lowercase too."],"exampleFix":"// before\n[{\"op\": \"replace\", \"path\": \"/secret\", \"value\": \"x\"}] // denied path\n// after\n[{\"op\": \"replace\", \"path\": \"/clientName\", \"value\": \"New Name\"}]","handlingStrategy":"validation","validationCode":"// Mirror the server's deny list client-side\nvar deny = glob.MustCompile(\"{/secret,/credentials}\", '/')\nfor _, op := range patchOps {\n    if deny.Match(strings.ToLower(op[\"path\"].(string))) {\n        return fmt.Errorf(\"path %v is not patchable\", op[\"path\"])\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Know the endpoint's denied paths and skip them in patch builders.","Use dedicated APIs (PUT/credentials endpoint) to change protected fields.","Match paths case-insensitively since the server lowercases them."],"tags":["json-patch","authorization","validation"],"backgroundTag":"patched-denied-path","analyzedSha":"4174065ffb052799890f7480f5360a877a67ffc1","analyzedAt":"2026-09-03T14:52:41.581Z","contentChangedAt":"2026-09-03T14:52:41.581Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}