FasterXML/jackson-databind · error · IllegalStateException
AnnotationIntrospector returned deserializer definition of t
Error message
AnnotationIntrospector returned deserializer definition of type {}; expected type `ValueDeserializer` or `Class<ValueDeserializer>` instead What it means
Thrown by DeserializationContextExt.deserializerInstance when the object returned for a deserializer definition is neither a ValueDeserializer instance nor a Class. The introspector (or @JsonDeserialize(using=...)) must yield one of those two shapes (or null); anything else violates the contract.
Source
Thrown at src/main/java/tools/jackson/databind/deser/DeserializationContextExt.java:246
/**********************************************************************
*/
@SuppressWarnings("unchecked")
@Override
public ValueDeserializer<Object> deserializerInstance(Annotated ann, Object deserDef)
{
if (deserDef == null) {
return null;
}
ValueDeserializer<?> deser;
if (deserDef instanceof ValueDeserializer valueDeserializer) {
deser = valueDeserializer;
} else {
// Alas, there's no way to force return type of "either class
// X or Y" -- need to throw an exception after the fact
if (!(deserDef instanceof Class)) {
throw new IllegalStateException("AnnotationIntrospector returned deserializer definition of type "
+deserDef.getClass().getName()
+"; expected type `ValueDeserializer` or `Class<ValueDeserializer>` instead");
}
Class<?> deserClass = (Class<?>)deserDef;
// there are some known "no class" markers to consider too:
if (deserClass == ValueDeserializer.None.class || ClassUtil.isBogusClass(deserClass)) {
return null;
}
if (!ValueDeserializer.class.isAssignableFrom(deserClass)) {
throw new IllegalStateException("AnnotationIntrospector returned `Class<"+deserClass.getName()+">`; expected `Class<ValueDeserializer>`");
}
HandlerInstantiator hi = _config.getHandlerInstantiator();
deser = (hi == null) ? null : hi.deserializerInstance(_config, ann, deserClass);
if (deser == null) {
deser = (ValueDeserializer<?>) ClassUtil.createInstance(deserClass,
_config.canOverrideAccessModifiers());
}
}View on GitHub (pinned to a50c7d2a1d)
Solutions
- Audit the introspector's deserializer-returning methods: return null, a ValueDeserializer instance, or a Class<? extends ValueDeserializer>.
- If resolving handlers by name, resolve the actual Class first and return that.
- Add a contract unit test covering all code paths of the introspector method.
Example fix
// before
public Object findDeserializer(Annotated a) {
return "myCustomDeserializer"; // String -> throws
}
// after
public Object findDeserializer(Annotated a) {
return MyCustomDeserializer.class; // Class<? extends ValueDeserializer>
} Defensive patterns
Strategy: type-guard
Type guard
static boolean isLegalDeserializerDef(Object def) {
return def == null
|| def instanceof ValueDeserializer
|| (def instanceof Class<?> c && ValueDeserializer.class.isAssignableFrom(c));
} Prevention
- Introspector handler methods return null|instance|Class — never names, strings, or wrappers.
- If resolving handlers by name, resolve to the Class before returning.
- Centralize handler-def validation in a shared helper used by all introspector overrides.
When it happens
Trigger: A custom AnnotationIntrospector.findDeserializer (or equivalent) returns a String, a Type, a Supplier, a bean-name, or another wrapper instead of a ValueDeserializer instance or Class<ValueDeserializer>.
Common situations: A custom framework introspection layer that wraps handler refs in its own types; a library upgrade where the introspector contract tightened; an annotation pointing at a bean name instead of a class.
Related errors
- AnnotationIntrospector returned key deserializer definition
- AnnotationIntrospector returned `Class<{}>`; expected `Class
- AnnotationIntrospector returned key deserializer definition
- AnnotationIntrospector returned Converter definition of type
- AnnotationIntrospector returned Class {}; expected Class<Con
AI-assisted analysis of FasterXML/jackson-databind@a50c7d2a1d (2026-08-06).
Data as JSON: /api/errors/011c1d6476373aac.
Report an issue: GitHub.