FasterXML/jackson-databind · error · IllegalStateException

Cannot update `Map.Entry` values

Error message

Cannot update `Map.Entry` values

What it means

Thrown by POJOWrappedDeserializer.deserialize(JsonParser, DeserializationContext, Map.Entry result) — the update-in-place overload on the POJO-wrapped variant of MapEntryDeserializer. This variant deserializes Map.Entry from a JSON object with 'key' and 'value' fields (as opposed to a single-entry object). Like the base class, Map.Entry cannot be updated in-place, so it throws IllegalStateException with the message formatted with backtick-quoted Map.Entry.

Source

Thrown at src/main/java/tools/jackson/databind/deser/jdk/MapEntryDeserializer.java:522

                }

                t = p.nextToken(); // move to next property or END_OBJECT
            }

            if (t != JsonToken.END_OBJECT) {
                ctxt.reportInputMismatch(this,
                        "Problem deserializing `Map.Entry`; unexpected content after Object value: "
                                +JsonToken.valueDescFor(t));
            }

            return new AbstractMap.SimpleEntry<>(key, value);
        }
        
        @Override
        public Map.Entry<Object,Object> deserialize(JsonParser p, DeserializationContext ctxt,
                Map.Entry<Object,Object> result) throws JacksonException
        {
            throw new IllegalStateException("Cannot update `Map.Entry` values");
        }

        @Override
        public Object deserializeWithType(JsonParser p, DeserializationContext ctxt,
                TypeDeserializer typeDeserializer)
            throws JacksonException
        {
            // In future could check current token... for now this should be enough:
            return typeDeserializer.deserializeTypedFromObject(p, ctxt);
        }

        // Copied from `ContainerDeserializerBase`
        protected <BOGUS> BOGUS wrapAndThrow(DeserializationContext ctxt,
                Throwable t, Object ref, String key) throws JacksonException
        {
            while (t instanceof InvocationTargetException && t.getCause() != null) {
                t = t.getCause();
            }

View on GitHub (pinned to a50c7d2a1d)

Solutions

  1. Do not use update-in-place APIs with Map.Entry — deserialize fresh each time.
  2. If POJO-wrapped format is needed, read into a new Map.Entry rather than updating.
  3. Use a custom POJO with 'key' and 'value' fields if you need both POJO format and update semantics.
  4. Avoid the three-argument deserialize overload for any Map.Entry variant.

Example fix

// before: update on POJO-wrapped entry
mapper.readerForUpdating(oldEntry).readValue("{\"key\":1,\"value\":2}");
// after: fresh deserialize
Map.Entry<Integer,Integer> e = mapper.readValue("{\"key\":1,\"value\":2}",
    new TypeReference<Map.Entry<Integer,Integer>>() {});
Defensive patterns

Strategy: try-catch

Validate before calling

// Detect POJO-wrapped Map.Entry and avoid update paths
if (Map.Entry.class.isAssignableFrom(targetType)) {
    // POJOWrappedDeserializer also rejects updates
    throw new UnsupportedOperationException(
        "Cannot update Map.Entry (POJO-wrapped) — deserialize fresh");
}

Type guard

static boolean isUpdatable(Class<?> type) {
    return !Map.Entry.class.isAssignableFrom(type);
}

Try / catch

try {
    mapper.readerForUpdating(oldEntry).readValue("{\"key\":1,\"value\":2}");
} catch (IllegalStateException e) {
    if (e.getMessage().contains("Cannot update `Map.Entry`")) {
        entry = mapper.readValue(json, entryTypeRef);
    }
}

Prevention

When it happens

Trigger: Calling mapper.readerForUpdating(existingEntry).readValue(json) where the entry uses the POJO-wrapped format (JSON like {"key":...,"value":...}). Any update-path that routes through POJOWrappedDeserializer for a Map.Entry type. Using ObjectReader.updateValue() on a Map.Entry configured for POJO-wrapped shape.

Common situations: Configuring @JsonFormat(shape=ANY) or ACCEPT_CASE_INSENSITIVE_PROPERTIES on a Map.Entry type and then attempting update. Using JsonFormat.Value for Map.Entry to force POJO-wrapped format. Round-tripping through update APIs after switching the entry deserialization format.

Related errors


AI-assisted analysis of FasterXML/jackson-databind@a50c7d2a1d (2026-08-06). Data as JSON: /api/errors/779760419e063947. Report an issue: GitHub.