FasterXML/jackson-databind · error · IllegalArgumentException

Trying to resolve a forward reference with id

Error message

Trying to resolve a forward reference with id [${id.toString()}] that wasn't previously registered.

What it means

Thrown by AnySetterReferring.handleResolvedForwardReference when an @JsonIdentityInfo forward reference is resolved with an id that was never registered as pending. The any-setter maintains a set of seen ids; resolving one that does not exist means the id stream is inconsistent with what was recorded during deserialization.

Solutions

  1. Let Jackson resolve forward references automatically instead of calling handleResolvedForwardReference yourself.
  2. Ensure the JSON was produced by a serializer using the same @JsonIdentityInfo configuration so every resolved id has a matching pending forward reference.
  3. If resolving manually, check hasId(id) before calling handleResolvedForwardReference and skip unknown ids.
  4. Verify there is no second ObjectMapper instance serializing/deserializing with a different identity-info scheme.

Example fix

// before
roid.handleResolvedForwardReference(ctxt, id, value); // id unknown -> throws

// after
if (roid.hasId(id)) {
    roid.handleResolvedForwardReference(ctxt, id, value);
} else {
    // log / skip unknown id
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!roid.hasId(id)) {
    // skip; id was never pending
    return;
}

Type guard

// no static type guard; runtime membership check via hasId(Object)

Try / catch

try { roid.handleResolvedForwardReference(ctxt, id, value); }
catch (IllegalArgumentException e) {
    if (e.getMessage().contains("wasn't previously registered")) {
        // log and skip the unknown id
    } else throw e;
}

Prevention

When it happens

Trigger: Manually calling ObjectIdResolver.resolveReference with an id that was not encountered as unresolved; using @JsonIdentityInfo on a type involved in an @JsonAnySetter where the JSON content for object ids is malformed or reordered; mixing manually-resolved forward references with the framework's own bookkeeping.

Common situations: Hand-rolled code that calls bindReference/handleResolvedForwardReference directly; corrupted JSON where an @id has no preceding forward reference; concurrent deserialization sharing a ReadableObjectId store; partial deserialization (e.g. @JsonIdentityInfo + custom parser) losing pending ids.

Related errors


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

Appendix: source

Thrown at src/main/java/tools/jackson/databind/deser/SettableAnyProperty.java:298

        private final SettableAnyProperty _parent;
        private final Object _pojo;
        private final String _propName;

        public AnySetterReferring(SettableAnyProperty parent,
                UnresolvedForwardReference reference, Class<?> type, Object instance, String propName)
        {
            super(reference, type);
            _parent = parent;
            _pojo = instance;
            _propName = propName;
        }

        @Override
        public void handleResolvedForwardReference(DeserializationContext ctxt, Object id, Object value)
            throws JacksonException
        {
            if (!hasId(id)) {
                throw new IllegalArgumentException("Trying to resolve a forward reference with id [" + id.toString()
                        + "] that wasn't previously registered.");
            }
            _parent.set(ctxt, _pojo, _propName, value);
        }
    }

    /*
    /**********************************************************************
    /* Concrete implementations
    /**********************************************************************
     */

    protected static class MethodAnyProperty extends SettableAnyProperty
    {
        public MethodAnyProperty(BeanProperty property,
                AnnotatedMember field, JavaType valueType,
                KeyDeserializer keyDeser,
                ValueDeserializer<Object> valueDeser, TypeDeserializer typeDeser) {

View on GitHub (pinned to 87876ca5c0)