FasterXML/jackson-databind · error · IllegalArgumentException

Unsuitable method ( ) decorated with @JsonCreator (for Enum…

Error message

Unsuitable method ({}) decorated with @JsonCreator (for Enum type {})

What it means

Thrown by BasicDeserializerFactory when an enum type has a static factory method annotated @JsonCreator that Jackson wants to use for key (EnumMap/Enum key) deserialization, but the method signature is unsuitable. For the key-deserializer path, the factory must take exactly one parameter of type String and return a type assignable to the enum class; otherwise this error is raised.

Solutions

  1. Ensure the @JsonCreator static factory used for enum key deserialization takes a single String argument and returns the enum type.
  2. If the method is meant for value (not key) deserialization, move/annotate a separate String-arg factory, or remove @JsonCreator from the unsuitable method.
  3. Use @JsonCreator(mode=Mode.DELEGATING) on a single-arg delegating constructor/factory with a String-compatible type.

Example fix

// before: int parameter -> unsuitable for enum key deser
public enum Code {
    @JsonCreator public static Code fromCode(int v){...}
}

// after: separate String-arg factory for key deser
public enum Code {
    @JsonCreator public static Code fromKey(String name){...}
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the enum's @JsonCreator factory: single String param, return type assignable to enum.
for (Method m : enumClass.getMethods()) {
    if (m.isAnnotationPresent(JsonCreator.class)
        && Modifier.isStatic(m.getModifiers())
        && (m.getParameterCount() != 1 || m.getParameterTypes()[0] != String.class
            || !enumClass.isAssignableFrom(m.getReturnType()))) {
        throw new IllegalStateException("Unsuitable enum creator: " + m);
    }
}

Type guard

boolean isEnumKeyFactory(Method m, Class<? extends Enum> enumClass) {
    return Modifier.isStatic(m.getModifiers())
        && m.getParameterCount() == 1
        && m.getParameterTypes()[0] == String.class
        && enumClass.isAssignableFrom(m.getReturnType());
}

Prevention

When it happens

Trigger: An enum declares @JsonCreator on a static method that has zero/multiple parameters, a non-String parameter, or a return type that is not compatible with the enum class, and Jackson attempts to build an enum key deserializer that would use it.

Common situations: Annotating a generic fromJson(Map)/fromJson(int) factory with @JsonCreator expecting it to be used for enum keys; sharing a creator between value and key deserialization where only a String-arg factory is valid; refactor that changed the parameter type.

Related errors


AI-assisted analysis of FasterXML/jackson-databind@87876ca5c0 (2026-08-11). Data as JSON: /api/errors/71834f94d6b5e692. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/tools/jackson/databind/deser/BasicDeserializerFactory.java:1283

                    Class<?> returnType = factory.getRawReturnType();
                    // usually should be class, but may be just plain Enum<?> (for Enum.valueOf()?)
                    if (returnType.isAssignableFrom(enumClass)) {
                        // note: mostly copied from 'EnumDeserializer.deserializerForCreator(...)'
                        if (factory.getRawParameterType(0) != String.class) {
                            // [databind#2725]: Should not error out because (1) there may be good creator
                            //   method and (2) this method may be valid for "regular" enum value deserialization
                            // (leaving aside potential for multiple conflicting creators)
//                            throw new IllegalArgumentException("Parameter #0 type for factory method ("+factory+") not suitable, must be java.lang.String");
                            continue;
                        }
                        if (config.canOverrideAccessModifiers()) {
                            ClassUtil.checkAndFixAccess(factory.getMember(),
                                    ctxt.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
                        }
                        return JDKKeyDeserializers.constructEnumKeyDeserializer(enumRes, factory, byEnumNamingResolver, byToStringResolver, byIndexResolver);
                    }
                }
                throw new IllegalArgumentException("Unsuitable method ("+factory+") decorated with @JsonCreator (for Enum type "
                        +enumClass.getName()+")");
            }
        }
        // Also, need to consider @JsonValue, if one found
        return JDKKeyDeserializers.constructEnumKeyDeserializer(enumRes, byEnumNamingResolver, byToStringResolver, byIndexResolver);
    }

    /*
    /**********************************************************************
    /* DeserializerFactory impl: find explicitly supported types
    /**********************************************************************
     */

    /**
     * Method that can be used to check if databind module has deserializer
     * for given (likely JDK) type: explicit meaning that it is not automatically
     * generated for POJO.
     *<p>

View on GitHub (pinned to 87876ca5c0)