{"record":{"id":"8b7980714a41aa88","repo":"FasterXML/jackson-databind","slug":"annotationintrospector-returned-class-deserclass","errorCode":null,"errorMessage":"AnnotationIntrospector returned Class ${deserClass.getName()}; expected Class<KeyDeserializer>","messagePattern":"AnnotationIntrospector returned Class (.+?); expected Class<KeyDeserializer>","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/main/java/tools/jackson/databind/deser/DeserializationContextExt.java","lineNumber":293,"sourceCode":"        }\n\n        KeyDeserializer deser;\n\n        if (deserDef instanceof KeyDeserializer keyDeserializer) {\n            deser = keyDeserializer;\n        } else {\n            if (!(deserDef instanceof Class)) {\n                throw new IllegalStateException(\"AnnotationIntrospector returned key deserializer definition of type \"\n                        +deserDef.getClass().getName()\n                        +\"; expected type KeyDeserializer or Class<KeyDeserializer> instead\");\n            }\n            Class<?> deserClass = (Class<?>)deserDef;\n            // there are some known \"no class\" markers to consider too:\n            if (deserClass == KeyDeserializer.None.class || ClassUtil.isBogusClass(deserClass)) {\n                return null;\n            }\n            if (!KeyDeserializer.class.isAssignableFrom(deserClass)) {\n                throw new IllegalStateException(\"AnnotationIntrospector returned Class \"+deserClass.getName()\n                        +\"; expected Class<KeyDeserializer>\");\n            }\n            HandlerInstantiator hi = _config.getHandlerInstantiator();\n            deser = (hi == null) ? null : hi.keyDeserializerInstance(_config, ann, deserClass);\n            if (deser == null) {\n                deser = (KeyDeserializer) ClassUtil.createInstance(deserClass,\n                        _config.canOverrideAccessModifiers());\n            }\n        }\n        // First: need to resolve\n        deser.resolve(this);\n        return deser;\n    }\n\n    /*\n    /**********************************************************************\n    /* Extended API, read methods\n    /**********************************************************************","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/FasterXML/jackson-databind/blob/87876ca5c0569b4933aec2d30d6225e4b9ba3a43/src/main/java/tools/jackson/databind/deser/DeserializationContextExt.java#L275-L311","documentation":"Thrown when keyDeserializerInstance receives a Class as the key-deserializer definition, but that Class does not extend KeyDeserializer. This is the class-typed sibling of error 41: the value is a Class (so it passed the first check) but it is the wrong kind of class.","triggerScenarios":"@JsonDeserialize(keyUsing = SomeClass.class) where SomeClass does not extend KeyDeserializer; an AnnotationIntrospector returning Class<ValueDeserializer> or any unrelated Class for a map key deserializer.","commonSituations":"Reusing a value deserializer class for map keys; forgetting that key deserializers must extend KeyDeserializer specifically; refactor that changed a class's hierarchy after it was referenced in annotations.","solutions":["Ensure the referenced class extends tools.jackson.databind.KeyDeserializer and overrides deserializeKey(String, DeserializationContext).","If you intended a value deserializer, register it via @JsonDeserialize(contentUsing = ...) instead of keyUsing.","Return KeyDeserializer.None.class or null to disable the custom key deserializer."],"exampleFix":"// before\n@JsonDeserialize(keyUsing = MyValueDeserializer.class)\nMap<String,V> map; // MyValueDeserializer extends ValueDeserializer, not KeyDeserializer\n\n// after\n@JsonDeserialize(keyUsing = MyKeyDeserializer.class)\nMap<String,V> map; // MyKeyDeserializer extends KeyDeserializer","handlingStrategy":"validation","validationCode":"Class<?> c = (Class<?>) def;\nif (c != null && c != KeyDeserializer.None.class\n        && !KeyDeserializer.class.isAssignableFrom(c)) {\n    throw new IllegalStateException(\"Not a KeyDeserializer: \" + c);\n}","typeGuard":"static boolean isKeyDeserializerClass(Class<?> c) {\n    return c != null && c != KeyDeserializer.None.class\n        && KeyDeserializer.class.isAssignableFrom(c);\n}","tryCatchPattern":"try { mapper.readValue(json, mapType); }\ncatch (IllegalStateException e) {\n    if (e.getMessage().contains(\"expected Class<KeyDeserializer>\")) {\n        // referenced class must extend KeyDeserializer\n    } else throw e;\n}","preventionTips":["Key deserializers extend KeyDeserializer; value deserializers extend ValueDeserializer. Confirm before referencing in @JsonDeserialize(keyUsing=...).","Keep a project-wide list of key vs value deserializer classes to avoid mix-ups."],"tags":["deserialization","key-deserializer","annotation-introspector","configuration","type-mismatch"],"backgroundTag":null,"analyzedSha":"87876ca5c0569b4933aec2d30d6225e4b9ba3a43","analyzedAt":"2026-08-11T12:55:24.033Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}