FasterXML/jackson-databind · error · IllegalArgumentException
Missing constructor (broken JDK (de)serialization?)
Error message
Missing constructor (broken JDK (de)serialization?)
What it means
InnerClassProperty's JDK-deserialization constructor failed to recover the inner-class Constructor from the AnnotatedConstructor wrapper. InnerClassProperty instances are Java-serializable, and on readObject the transient Constructor must be rebuilt from the annotated form; if the annotated form is null (corrupted stream or a subclass that nulled _annotated), the instance cannot be reconstructed.
Source
Thrown at src/main/java/tools/jackson/databind/deser/impl/InnerClassProperty.java:49
public InnerClassProperty(SettableBeanProperty delegate,
Constructor<?> ctor)
{
super(delegate);
_creator = ctor;
}
/**
* Constructor used with JDK Serialization; needed to handle transient
* Constructor, wrap/unwrap in/out-of Annotated variant.
*/
protected InnerClassProperty(SettableBeanProperty src, AnnotatedConstructor ann)
{
super(src);
_annotated = ann;
_creator = (_annotated == null) ? null : _annotated.getAnnotated();
if (_creator == null) {
throw new IllegalArgumentException("Missing constructor (broken JDK (de)serialization?)");
}
}
@Override
protected SettableBeanProperty withDelegate(SettableBeanProperty d) {
if (d == this.delegate) {
return this;
}
return new InnerClassProperty(d, _creator);
}
/*
/**********************************************************
/* Deserialization methods
/**********************************************************
*/
@OverrideView on GitHub (pinned to 87876ca5c0)
Solutions
- Do not Java-serialize Jackson deserializers; rebuild the ObjectMapper in the target JVM instead.
- Ensure both sides of Java serialization run the same Jackson version and have the same inner class on the classpath.
- If you must transport state, serialize the configuration (modules, mixins) and rebuild the mapper, not the deserializer instances.
- Upgrade Jackson on both ends; older versions had known bugs in InnerClassProperty re-resolution.
Example fix
// before ObjectOutputStream out = ...; out.writeObject(mapper.getDeserializerFor(Foo.class)); // later readObject -> throws // after (rebuild in target JVM) ObjectMapper mapper = JsonMapper.builder().addModule(...).build(); ValueDeserializer<Foo> d = mapper.getDeserializerFor(Foo.class);
Defensive patterns
Strategy: retry
Validate before calling
// cannot validate from user code; avoid Java-serializing deserializers
Type guard
// no type guard; recovery is rebuilding the mapper
Try / catch
try { (ObjectInputStream) in.readObject(); }
catch (IllegalArgumentException e) {
if (e.getMessage().contains("broken JDK (de)serialization")) {
// rebuild ObjectMapper locally instead of transporting it
} else throw e;
} Prevention
- Never Java-serialize Jackson deserializer/mapper instances; serialize configuration and rebuild.
- Keep Jackson version identical on both ends of any reflective serialization.
When it happens
Trigger: Java-serializing a BeanDeserializer that contains an InnerClassProperty and deserializing it in a JVM/classloader where the AnnotatedConstructor cannot be re-resolved; a corrupted or hand-crafted serialized stream; subclassing InnerClassProperty and clearing _annotated.
Common situations: Distributing pre-built ObjectMapper/deserializer caches via Java serialization across mismatched Jackson versions; classloader boundary changes (modular runtime, OSGi) where reflection metadata is unavailable; tests that serialize/deserialize deserializers directly.
Related errors
- Property '${getName()}' already had index (${_propertyIndex}
- Can only call after BeanDeserializer has been resolved
- No entry '${oldProp.getName()}' found, can't replace
- Should not call set() on ObjectIdProperty that has no Settab
- AnnotationIntrospector returned Converter definition of type
AI-assisted analysis of FasterXML/jackson-databind@87876ca5c0 (2026-08-11).
Data as JSON: /api/errors/c637e573619401da.
Report an issue: GitHub.