{"record":{"id":"c637e573619401da","repo":"FasterXML/jackson-databind","slug":"missing-constructor-broken-jdk-de-serialization","errorCode":null,"errorMessage":"Missing constructor (broken JDK (de)serialization?)","messagePattern":"Missing constructor \\(broken JDK \\(de\\)serialization\\?\\)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/tools/jackson/databind/deser/impl/InnerClassProperty.java","lineNumber":49,"sourceCode":"\n    public InnerClassProperty(SettableBeanProperty delegate,\n            Constructor<?> ctor)\n    {\n        super(delegate);\n        _creator = ctor;\n    }\n\n    /**\n     * Constructor used with JDK Serialization; needed to handle transient\n     * Constructor, wrap/unwrap in/out-of Annotated variant.\n     */\n    protected InnerClassProperty(SettableBeanProperty src, AnnotatedConstructor ann)\n    {\n        super(src);\n        _annotated = ann;\n        _creator = (_annotated == null) ? null : _annotated.getAnnotated();\n        if (_creator == null) {\n            throw new IllegalArgumentException(\"Missing constructor (broken JDK (de)serialization?)\");\n        }\n    }\n\n    @Override\n    protected SettableBeanProperty withDelegate(SettableBeanProperty d) {\n        if (d == this.delegate) {\n            return this;\n        }\n        return new InnerClassProperty(d, _creator);\n    }\n\n    /*\n    /**********************************************************\n    /* Deserialization methods\n    /**********************************************************\n     */\n\n    @Override","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/FasterXML/jackson-databind/blob/87876ca5c0569b4933aec2d30d6225e4b9ba3a43/src/main/java/tools/jackson/databind/deser/impl/InnerClassProperty.java#L31-L67","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nObjectOutputStream out = ...;\nout.writeObject(mapper.getDeserializerFor(Foo.class)); // later readObject -> throws\n\n// after (rebuild in target JVM)\nObjectMapper mapper = JsonMapper.builder().addModule(...).build();\nValueDeserializer<Foo> d = mapper.getDeserializerFor(Foo.class);","handlingStrategy":"retry","validationCode":"// cannot validate from user code; avoid Java-serializing deserializers","typeGuard":"// no type guard; recovery is rebuilding the mapper","tryCatchPattern":"try { (ObjectInputStream) in.readObject(); }\ncatch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"broken JDK (de)serialization\")) {\n        // rebuild ObjectMapper locally instead of transporting it\n    } else throw e;\n}","preventionTips":["Never Java-serialize Jackson deserializer/mapper instances; serialize configuration and rebuild.","Keep Jackson version identical on both ends of any reflective serialization."],"tags":["deserialization","inner-class","jdk-serialization","internal"],"backgroundTag":null,"analyzedSha":"87876ca5c0569b4933aec2d30d6225e4b9ba3a43","analyzedAt":"2026-08-11T12:55:24.033Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}