FasterXML/jackson-databind · error · IllegalStateException

Cannot update Map.Entry values

Error message

Cannot update Map.Entry values

What it means

Map.Entry values are treated as immutable by the default MapEntryDeserializer; the three-argument deserialize(p, ctxt, resultToUpdate) override unconditionally throws IllegalStateException. Jackson's 'update/merge' API (readerForUpdating, updateValue) requires the deserializer to support in-place updates, which a single-entry key/value pair cannot do meaningfully.

Solutions

  1. Replace Map.Entry with a mutable pair type (e.g. AbstractMap.SimpleEntry, or a custom Pair class with setters).
  2. Deserialize into a fresh Map.Entry each time instead of updating an existing one.
  3. If merging is required, deserialize to a Map and construct a new entry from the merged result.

Example fix

// before
Map.Entry<String,Integer> entry = ...;
entry = mapper.readerForUpdating(entry).readValue(json); // throws

// after
AbstractMap.SimpleEntry<String,Integer> entry = ...;
entry = mapper.readerForUpdating(new AbstractMap.SimpleEntry<>(entry.getKey(), entry.getValue())).readValue(json);
Defensive patterns

Strategy: try-catch

Validate before calling

if (target instanceof Map.Entry && operation == UPDATE) {
    throw new UnsupportedOperationException(
        "Map.Entry is immutable; use AbstractMap.SimpleEntry for updates");
}

Type guard

boolean isUpdatablePairType(Class<?> c) {
    return c != null
        && !Map.Entry.class.isAssignableFrom(c);
}

Try / catch

try {
    mapper.readerForUpdating(entry).readValue(json);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("Map.Entry")) {
        // fall back to fresh deserialization
        entry = mapper.readValue(json, new TypeReference<Map.Entry<K,V>>(){});
    } else throw e;
}

Prevention

When it happens

Trigger: Calling objectMapper.readerForUpdating(existingEntry).readValue(json) where the target is a Map.Entry; invoking mapper.updateValue(entry, jsonNode) with a Map.Entry instance; using ObjectReaderToUpdate patterns against a Map.Entry-typed property.

Common situations: Treating Map.Entry as a mutable POJO; migrating code that used a Pair-like class to Map.Entry; JSON patch/merge APIs applied to entry types; frameworks that generically call updateValue on every field type.

Related errors


AI-assisted analysis of FasterXML/jackson-databind@87876ca5c0 (2026-08-11). Data as JSON: /api/errors/5ee26272ea2f1ecb. Report an issue: GitHub.

Appendix: source

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

            if (t == JsonToken.PROPERTY_NAME) { // most likely
                ctxt.reportInputMismatch(this,
                        "Problem binding JSON into Map.Entry: more than one entry in JSON (second field: '%s')",
                        p.currentName());
            } else {
                // how would this occur?
                ctxt.reportInputMismatch(this,
                        "Problem binding JSON into Map.Entry: unexpected content after JSON Object entry: "+t);
            }
            return null;
        }
        return new AbstractMap.SimpleEntry<Object,Object>(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);
    }

    /*
    /**********************************************************************
    /* Alternate handlers
    /**********************************************************************
     */

    /**

View on GitHub (pinned to 87876ca5c0)