{"record":{"id":"e8846c121e857e41","repo":"ory/hydra","slug":"error-parsing-patch-operations-v","errorCode":null,"errorMessage":"error parsing patch operations: %v","messagePattern":"error parsing patch operations: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"oryx/jsonx/patch.go","lineNumber":69,"sourceCode":"\tpatch, err := jsonpatch.DecodePatch(p)\n\tif err != nil {\n\t\treturn result, errors.WithStack(err)\n\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()","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/oryx/jsonx/patch.go#L51-L87","documentation":"After allow-listing the operation kind, ApplyJSONPatch calls op.Path() on each decoded JSON Patch operation. If the operation object is malformed — most commonly a 'move' or 'copy' operation that carries 'from' but no 'path', or a non-string/missing 'path' field — evanphx/json-patch fails to extract the path and this error wraps that failure.","triggerScenarios":"Calling ApplyJSONPatch with an operation entry missing the required \"path\" member or with a non-string path value, e.g. [{\"op\":\"remove\"}] or {\"op\":\"add\",\"path\":123}. Reached via patchOAuth2Client with a hand-crafted PATCH body.","commonSituations":"Buggy client-side patch builders, serializers that drop empty strings, or move/copy operations that only set 'from'. Also seen when a patch is double-encoded JSON or manually assembled incorrectly.","solutions":["Ensure every operation in the patch document includes a string \"path\" member per RFC 6902.","Validate the patch client-side with a JSON Patch schema before sending.","Replace move/copy operations (which often lack 'path' handling here) with explicit add/remove operations.","Check that the request body is not double-encoded: send the patch array directly, not as a JSON string."],"exampleFix":"// before\n[{\"op\": \"remove\"}]\n// after\n[{\"op\": \"remove\", \"path\": \"/name\"}]","handlingStrategy":"validation","validationCode":"for _, op := range patchOps {\n    p, ok := op[\"path\"].(string)\n    if !ok || p == \"\" {\n        return fmt.Errorf(\"every patch operation needs a string 'path'\")\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate the patch document with a JSON Patch schema before sending.","Ensure the body is a JSON array, not a double-encoded string.","Avoid move/copy ops that omit 'path'."],"tags":["json-patch","rfc6902","malformed-request"],"backgroundTag":"malformed-json-patch","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"}