{"record":{"id":"9c24b739f2d2973e","repo":"json-path/JsonPath","slug":"invalid-put-operation-is-not-a-map","errorCode":null,"errorMessage":"Invalid put operation. $ is not a map","messagePattern":"Invalid put operation\\. \\$ is not a map","errorType":"exception","errorClass":"InvalidModificationException","httpStatus":null,"severity":"error","filePath":"json-path/src/main/java/com/jayway/jsonpath/internal/PathRef.java","lineNumber":136,"sourceCode":"        public void delete(Configuration configuration) {\n            throw new InvalidModificationException(\"Invalid delete operation\");\n        }\n\n        @Override\n        public void add(Object newVal, Configuration configuration) {\n            if(configuration.jsonProvider().isArray(parent)){\n                configuration.jsonProvider().setArrayIndex(parent, configuration.jsonProvider().length(parent), newVal);\n            } else {\n                throw new InvalidModificationException(\"Invalid add operation. $ is not an array\");\n            }\n        }\n\n        @Override\n        public void put(String key, Object newVal, Configuration configuration) {\n            if(configuration.jsonProvider().isMap(parent)){\n                configuration.jsonProvider().setProperty(parent, key, newVal);\n            } else {\n                throw new InvalidModificationException(\"Invalid put operation. $ is not a map\");\n            }\n        }\n\n        @Override\n        public void renameKey(String oldKeyName, String newKeyName, Configuration configuration) {\n            Object target = parent;\n            if(targetInvalid(target)){\n                return;\n            }\n            renameInMap(target, oldKeyName, newKeyName, configuration);\n        }\n\n    }\n\n    private static class ArrayIndexPathRef extends PathRef {\n\n        private int index;\n","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/json-path/JsonPath/blob/62a4c9f0f65ba3f625aa0867d64c528ba72d09ec/json-path/src/main/java/com/jayway/jsonpath/internal/PathRef.java#L118-L154","documentation":"The root ('$') PathRef.put sets a key/value pair on the root only if the root is a JSON map. When the root is an array or scalar, put is impossible, so it throws InvalidModificationException 'Invalid put operation. $ is not a map'.","triggerScenarios":"Calling JsonPath.put(document, \"$\", key, newVal, configuration) where the parsed root is an array (e.g. a JSON array document) or any non-object value.","commonSituations":"Documents returned as top-level JSON arrays while code assumes an object root; putting a field at the wrong level — the target object is a nested property, not the root; endpoints whose payload shape changed between versions.","solutions":["Verify the root is a map (configuration.jsonProvider().isMap(root)) before putting.","Put the key at the correct nested path, e.g. JsonPath.put(document, \"$.settings\", key, value, conf).","If the root is an array, address a specific element: \"$.\" + index or \"$[i]\" then put there.","Normalize/wrap array-root documents into an object before applying key-based mutations."],"exampleFix":"// before\nJsonPath.put(document, \"$\", \"version\", 2, conf); // root is an array\n// after\nJsonPath.put(document, \"$.meta\", \"version\", 2, conf);","handlingStrategy":"type-guard","validationCode":"Object root = JsonPath.parse(document).json();\nif (!(root instanceof Map)) {\n    throw new IllegalArgumentException(\"Root is not a map; put keys on a nested object path instead\");\n}","typeGuard":"boolean rootIsMap(Object doc, Configuration conf) {\n    Object root = JsonPath.parse(doc, conf).json();\n    return conf.jsonProvider().isMap(root);\n}","tryCatchPattern":"try {\n    JsonPath.put(document, \"$\", key, newVal, conf);\n} catch (InvalidModificationException e) {\n    throw new IllegalStateException(\"Root of document is not a JSON object; cannot put '\" + key + \"'\", e);\n}","preventionTips":["Confirm the root is a JSON object before key-based mutations","Put at the correct nested path (e.g. $.meta) rather than \"$\"","Handle endpoints that return top-level arrays by wrapping or addressing elements","Pin response schemas with contract tests to catch shape drift early"],"tags":["json-path","put-operation","root-path","map"],"backgroundTag":"type-mismatch","analyzedSha":"62a4c9f0f65ba3f625aa0867d64c528ba72d09ec","analyzedAt":"2026-09-11T11:36:00.448Z","contentChangedAt":"2026-09-11T11:36:00.448Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}