FasterXML/jackson-databind · error · IllegalArgumentException

Cannot handle managed/back reference '{}': type: value deser

Error message

Cannot handle managed/back reference '{}': type: value deserializer of type {} does not support them

What it means

ValueDeserializer.findBackReference(String) is, by default in the base class, a fail-loud stub: it throws because the base ValueDeserializer does not understand managed/back references (@JsonBackReference/@JsonManagedReference). Only specific deserializers (notably BeanDeserializer) override it to return the matching SettableBeanProperty. If a deserializer that doesn't support references is wired into a bidirectional parent/child relationship, this error surfaces during deserializer construction.

Source

Thrown at src/main/java/tools/jackson/databind/ValueDeserializer.java:456

     * Default implementation returns null, as support cannot be implemented
     * generically. Some standard deserializers (most notably
     * {@link tools.jackson.databind.deser.bean.BeanDeserializer})
     * do implement this feature, and may return reader instance, depending on exact
     * configuration of instance (which is based on type, and referring property).
     *
     * @return ObjectIdReader used for resolving possible Object Identifier
     *    value, instead of full value serialization, if deserializer can do that;
     *    null if no Object Id is expected.
     */
    public ObjectIdReader getObjectIdReader(DeserializationContext ctxt) { return null; }

    /**
     * Method needed by {@link BeanDeserializerFactory} to properly link
     * managed- and back-reference pairs.
     */
    public SettableBeanProperty findBackReference(String refName)
    {
        throw new IllegalArgumentException("Cannot handle managed/back reference '"+refName
                +"': type: value deserializer of type "+getClass().getName()+" does not support them");
    }

    /**
     * Introspection method that may be called to see whether deserializer supports
     * update of an existing value (aka "merging") or not. Return value should either
     * be {@link Boolean#FALSE} if update is not supported at all (immutable values);
     * {@link Boolean#TRUE} if update should usually work (regular POJOs, for example),
     * or <code>null</code> if this is either not known, or may sometimes work.
     *<p>
     * Information gathered is typically used to either prevent merging update for
     * property (either by skipping, if based on global defaults; or by exception during
     * deserializer construction if explicit attempt made) if {@link Boolean#FALSE}
     * returned, or inclusion if {@link Boolean#TRUE} is specified. If "unknown" case
     * (<code>null</code> returned) behavior is to exclude property if global defaults
     * used; or to allow if explicit per-type or property merging is defined.
     *<p>
     * Default implementation returns <code>null</code> to allow explicit per-type

View on GitHub (pinned to a50c7d2a1d)

Solutions

  1. If the type genuinely needs managed/back references, ensure it is deserialized by a BeanDeserializer (POJO) — don't replace it with a custom ValueDeserializer, or have your custom deserializer extend BeanDeserializer / delegate reference handling.
  2. Override findBackReference in your custom ValueDeserializer to return the appropriate SettableBeanProperty (or wire references manually).
  3. Remove the @JsonManagedReference/@JsonBackReference annotations if the bidirectional linking isn't actually needed for that type, and handle cycles with @JsonIdentityInfo or @JsonIgnore instead.
  4. Split the type so the annotated side is a plain POJO handled by BeanDeserializer and the custom logic lives in a nested type.

Example fix

// before
public class Parent {
    @JsonManagedReference public List<Child> children;
}
public class Child {
    @JsonBackReference public Parent parent; // Child uses a custom ValueDeserializer -> throws
}
// after: let Child be a normal POJO deserialized by BeanDeserializer,
// or override in your custom ChildDeserializer:
@Override
public SettableBeanProperty findBackReference(String refName) {
    return _backRefs.get(refName); // populate during construction
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Only apply reference annotations to POJO types deserialized by BeanDeserializer
if (!BeanDeserializer.class.isAssignableFrom(deser.getClass())) {
    // do not rely on managed/back reference for this type
}

Type guard

boolean supportsBackRefs(ValueDeserializer<?> d) {
    try {
        // findBackReference throws by default in the base class
        return !(d.findBackReference("__probe__") == null && false);
    } catch (IllegalArgumentException e) {
        return false;
    }
}

Try / catch

try {
    return mapper.readValue(json, TypeWithRefs.class);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("does not support them")) {
        // remove reference annotations or switch to a BeanDeserializer-backed type
    }
    throw e;
}

Prevention

When it happens

Trigger: Annotating a field with @JsonManagedReference/@JsonBackReference on a type whose deserializer is a custom ValueDeserializer (not a BeanDeserializer) or a standard non-bean deserializer (collection, map, primitive, enum); using @JsonIdentityInfo or parent/child refs on a type that delegates to a custom deserializer that never implements findBackReference.

Common situations: Adding @JsonBackReference to a wrapper/holder type that is deserialized via a custom ValueDeserializer; bidirectional JPA entities where one side is mapped through a custom deserializer; converting a 2.x custom deserializer that extended JsonDeserializer without overriding findBackReference; mixing tree-model or collection deserializers with reference annotations.

Related errors


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