{"record":{"id":"128b9a93c47d984c","repo":"FasterXML/jackson-databind","slug":"annotationintrospector-returned-class-expec-128b9a","errorCode":null,"errorMessage":"AnnotationIntrospector returned `Class<{}>`; expected `Class<ValueDeserializer>`","messagePattern":"AnnotationIntrospector returned `Class<(.+?)>`; expected `Class<ValueDeserializer>`","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/main/java/tools/jackson/databind/deser/DeserializationContextExt.java","lineNumber":256,"sourceCode":"        ValueDeserializer<?> deser;\n\n        if (deserDef instanceof ValueDeserializer valueDeserializer) {\n            deser = valueDeserializer;\n        } else {\n            // Alas, there's no way to force return type of \"either class\n            // X or Y\" -- need to throw an exception after the fact\n            if (!(deserDef instanceof Class)) {\n                throw new IllegalStateException(\"AnnotationIntrospector returned deserializer definition of type \"\n                        +deserDef.getClass().getName()\n                        +\"; expected type `ValueDeserializer` or `Class<ValueDeserializer>` instead\");\n            }\n            Class<?> deserClass = (Class<?>)deserDef;\n            // there are some known \"no class\" markers to consider too:\n            if (deserClass == ValueDeserializer.None.class || ClassUtil.isBogusClass(deserClass)) {\n                return null;\n            }\n            if (!ValueDeserializer.class.isAssignableFrom(deserClass)) {\n                throw new IllegalStateException(\"AnnotationIntrospector returned `Class<\"+deserClass.getName()+\">`; expected `Class<ValueDeserializer>`\");\n            }\n            HandlerInstantiator hi = _config.getHandlerInstantiator();\n            deser = (hi == null) ? null : hi.deserializerInstance(_config, ann, deserClass);\n            if (deser == null) {\n                deser = (ValueDeserializer<?>) ClassUtil.createInstance(deserClass,\n                        _config.canOverrideAccessModifiers());\n            }\n        }\n        // First: need to resolve\n        deser.resolve(this);\n        return (ValueDeserializer<Object>) deser;\n    }\n\n    @Override\n    public final KeyDeserializer keyDeserializerInstance(Annotated ann, Object deserDef)\n    {\n        if (deserDef == null) {\n            return null;","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/FasterXML/jackson-databind/blob/a50c7d2a1d57234ac4adf70dbd88ac90db6436e4/src/main/java/tools/jackson/databind/deser/DeserializationContextExt.java#L238-L274","documentation":"Thrown by DeserializationContextExt.deserializerInstance when the introspector returns a Class for the deserializer, but that Class does not extend ValueDeserializer. Only ValueDeserializer subclasses can be instantiated to drive deserialization.","triggerScenarios":"@JsonDeserialize(using = MyClass.class) where MyClass does not extend ValueDeserializer, or a custom introspector returning a non-deserializer Class.","commonSituations":"Annotating a serializer, a converter, or a plain utility class with using= instead of a real deserializer; a refactor that dropped the extends ValueDeserializer clause; pointing at an interface that isn't a deserializer.","solutions":["Make the referenced class extend ValueDeserializer<T> and implement deserialize().","If you meant a serializer, use @JsonSerialize(using=...) instead.","Verify the class referenced in @JsonDeserialize(using=...)."],"exampleFix":"// before\n@JsonDeserialize(using = ItemFormatter.class) // not a ValueDeserializer\nclass ItemFormatter { String format(Item i){ ... } }\n// after\nclass ItemDeserializer extends ValueDeserializer<Item> {\n    @Override public Item deserialize(JsonParser p, DeserializationContext c){ ... }\n}\n@JsonDeserialize(using = ItemDeserializer.class)","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"static boolean isDeserializerClass(Class<?> c) {\n    return c != null && ValueDeserializer.class.isAssignableFrom(c);\n}","tryCatchPattern":null,"preventionTips":["Verify @JsonDeserialize(using=...) targets extend ValueDeserializer.","Don't confuse @JsonDeserialize(using=) (deserializer) with @JsonSerialize(using=) (serializer) or @JsonDeserialize(converter=).","Keep serializers and deserializers in distinctly named packages."],"tags":["annotation-introspector","deserializer","type-mismatch"],"analyzedSha":"a50c7d2a1d57234ac4adf70dbd88ac90db6436e4","analyzedAt":"2026-08-06T20:31:51.404Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}