{"record":{"id":"b75410a9e7cbdb36","repo":"FasterXML/jackson-databind","slug":"multiple-suitable-annotated-creator-factory-method","errorCode":null,"errorMessage":"Multiple suitable annotated Creator factory methods to be used as the Key deserializer for type ${rawKeyType}","messagePattern":"Multiple suitable annotated Creator factory methods to be used as the Key deserializer for type (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/tools/jackson/databind/deser/jdk/JDKKeyDeserializers.java","lineNumber":201,"sourceCode":"        }\n        return null;\n    }\n\n    private static AnnotatedMethod _findExplicitStringFactoryMethod(DeserializationContext ctxt,\n            List<AnnotatedAndMetadata<AnnotatedMethod, JsonCreator.Mode>> candidates)\n        throws JacksonException\n    {\n        AnnotatedMethod match = null;\n        for (AnnotatedAndMetadata<AnnotatedMethod, JsonCreator.Mode> entry : candidates) {\n            // Note: caller has filtered out invalid candidates; all we need to check are dups\n            if (entry.metadata != null) {\n                if (match == null) {\n                    match = entry.annotated;\n                } else {\n                    // 15-Jun-2021, tatu: Not optimal type or information, but has to do for now\n                    //    since we do not get DeserializationContext\n                    Class<?> rawKeyType = entry.annotated.getDeclaringClass();\n                    throw new IllegalArgumentException(\n\"Multiple suitable annotated Creator factory methods to be used as the Key deserializer for type \"\n                            +ClassUtil.nameOf(rawKeyType));\n                }\n            }\n        }\n        return match;\n    }\n\n    /*\n    /**********************************************************************\n    /* KeyDeserializers implementation\n    /**********************************************************************\n     */\n\n    @Override\n    public KeyDeserializer findKeyDeserializer(JavaType type,\n            DeserializationConfig config, BeanDescription.Supplier beanDescRef)\n    {","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/FasterXML/jackson-databind/blob/a50c7d2a1d57234ac4adf70dbd88ac90db6436e4/src/main/java/tools/jackson/databind/deser/jdk/JDKKeyDeserializers.java#L183-L219","documentation":"Thrown by JDKKeyDeserializers._findExplicitStringFactoryMethod when more than one factory method on a class is annotated as a suitable @JsonCreator for key deserialization. The method scans candidate factory methods (that accept a single String parameter) and expects exactly one match; finding a second annotated match is ambiguous and throws IllegalArgumentException. This is a bean-definition error for types used as Map keys.","triggerScenarios":"A class used as a Map key has two or more static factory methods annotated with @JsonCreator(Mode.DELEGATING or PROPERTIES) that each accept a single String. A valueOf-like factory and a fromString-like factory both marked as creators. Using @Jacksonized with a factory method when another factory method also qualifies.","commonSituations":"Adding a second factory method with @JsonCreator to a class used as a map key. Library types that provide both valueOf(String) and fromString(String) with one annotated as creator. Migrating from valueOf to fromString without removing the old creator annotation.","solutions":["Ensure only one factory method on the key type is annotated as a creator (@JsonCreator).","If the type has both valueOf and fromString, annotate only one — Jackson will auto-detect the other if needed.","Remove redundant @JsonCreator annotations from secondary factory methods.","Use a custom KeyDeserializer via SimpleModule.addKeyDeserializer if you need non-standard key parsing."],"exampleFix":"// before: two factory methods both annotated\n@JsonCreator public static Key fromString(String s) { ... }\n@JsonCreator public static Key valueOf(String s) { ... }\n// after: only one\n@JsonCreator public static Key fromString(String s) { ... }","handlingStrategy":"validation","validationCode":"// Check for duplicate @JsonCreator factory methods at startup\nList<Method> factoryMethods = Arrays.stream(MyKey.class.getMethods())\n    .filter(m -> m.isAnnotationPresent(JsonCreator.class))\n    .filter(m -> m.getParameterCount() == 1\n        && m.getParameterTypes()[0] == String.class)\n    .toList();\nif (factoryMethods.size() > 1) {\n    throw new IllegalStateException(\"Multiple key-deserializer factory methods\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    mapper.readValue(json, new TypeReference<Map<MyKey,String>>() {});\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Multiple suitable\")) {\n        // Remove duplicate @JsonCreator on key type factory methods\n    }\n}","preventionTips":["Annotate only one String-accepting factory method as @JsonCreator on key types.","If both valueOf and fromString exist, annotate at most one.","Use a custom KeyDeserializer for complex key parsing logic."],"tags":["jackson","deserialization","key-deserializer","ambiguous-creator","map-key"],"analyzedSha":"a50c7d2a1d57234ac4adf70dbd88ac90db6436e4","analyzedAt":"2026-08-06T20:31:51.404Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}