{"record":{"id":"779760419e063947","repo":"FasterXML/jackson-databind","slug":"cannot-update-map-entry-values-779760","errorCode":null,"errorMessage":"Cannot update `Map.Entry` values","messagePattern":"Cannot update `Map\\.Entry` values","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/main/java/tools/jackson/databind/deser/jdk/MapEntryDeserializer.java","lineNumber":522,"sourceCode":"                }\n\n                t = p.nextToken(); // move to next property or END_OBJECT\n            }\n\n            if (t != JsonToken.END_OBJECT) {\n                ctxt.reportInputMismatch(this,\n                        \"Problem deserializing `Map.Entry`; unexpected content after Object value: \"\n                                +JsonToken.valueDescFor(t));\n            }\n\n            return new AbstractMap.SimpleEntry<>(key, value);\n        }\n        \n        @Override\n        public Map.Entry<Object,Object> deserialize(JsonParser p, DeserializationContext ctxt,\n                Map.Entry<Object,Object> result) throws JacksonException\n        {\n            throw new IllegalStateException(\"Cannot update `Map.Entry` values\");\n        }\n\n        @Override\n        public Object deserializeWithType(JsonParser p, DeserializationContext ctxt,\n                TypeDeserializer typeDeserializer)\n            throws JacksonException\n        {\n            // In future could check current token... for now this should be enough:\n            return typeDeserializer.deserializeTypedFromObject(p, ctxt);\n        }\n\n        // Copied from `ContainerDeserializerBase`\n        protected <BOGUS> BOGUS wrapAndThrow(DeserializationContext ctxt,\n                Throwable t, Object ref, String key) throws JacksonException\n        {\n            while (t instanceof InvocationTargetException && t.getCause() != null) {\n                t = t.getCause();\n            }","sourceCodeStart":504,"sourceCodeEnd":540,"githubUrl":"https://github.com/FasterXML/jackson-databind/blob/87876ca5c0569b4933aec2d30d6225e4b9ba3a43/src/main/java/tools/jackson/databind/deser/jdk/MapEntryDeserializer.java#L504-L540","documentation":"The POJO-shaped variant of Map.Entry deserialization (MapEntryDeserializer.POJOWrappedDeserializer, used when Map.Entry is rendered as a {\"key\":...,\"value\":...} object) also rejects in-place updates: its deserialize(p, ctxt, resultToUpdate) throws IllegalStateException. Same immutability contract as the default deserializer, applied to the shape-shifting path.","triggerScenarios":"Calling updateValue or readerForUpdating against a Map.Entry that Jackson deserializes via the POJO-wrapped shape (e.g. when SPLIT shapes or specific config forces object-form reading); JSON-patch tooling that merges into a Map.Entry field.","commonSituations":"Configuring DeserializationFeature/JsonFormat shapes that trigger POJO wrapping for entries; reusing a deserialized entry across multiple update cycles; generic merge frameworks that recurse into all property types including entries.","solutions":["Use a mutable holder (AbstractMap.SimpleEntry or a dedicated Pair class) for any field that needs updates.","Avoid readerForUpdating/updateValue on Map.Entry-typed properties; deserialize fresh each time.","Force the non-POJO shape (or vice versa) only if it helps you avoid the update path; the immutability restriction applies to both shapes."],"exampleFix":"// before\npublic class PairBox { public Map.Entry<String,Integer> pair; }\nPairBox box = ...;\nbox = mapper.updateValue(box, patchJson); // throws when updating pair\n\n// after\npublic class PairBox { public AbstractMap.SimpleEntry<String,Integer> pair; }","handlingStrategy":"try-catch","validationCode":"if (target instanceof Map.Entry && operation == UPDATE) {\n    throw new UnsupportedOperationException(\n        \"POJO-wrapped Map.Entry is immutable; use AbstractMap.SimpleEntry\");\n}","typeGuard":"boolean isUpdatablePairType(Class<?> c) {\n    return c != null && !Map.Entry.class.isAssignableFrom(c);\n}","tryCatchPattern":"try {\n    mapper.updateValue(holder, patchJson);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"Map.Entry\")) {\n        holder.pair = mapper.convertValue(patchNode.get(\"pair\"),\n            new TypeReference<AbstractMap.SimpleEntry<K,V>>(){});\n    } else throw e;\n}","preventionTips":["Avoid updateValue on any holder whose fields include Map.Entry; switch the field to AbstractMap.SimpleEntry.","Pin the entry deserialization shape in tests so POJO-wrapped behavior is explicit.","Add a domain rule forbidding Map.Entry in mutable aggregates."],"tags":["deserialization","map-entry","update-value","pojo","immutability","illegal-state"],"backgroundTag":null,"analyzedSha":"87876ca5c0569b4933aec2d30d6225e4b9ba3a43","analyzedAt":"2026-08-11T12:55:24.033Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}