FasterXML/jackson-databind · error · IllegalArgumentException

Cannot pass null KeyDeserializers

Error message

Cannot pass null KeyDeserializers

What it means

Thrown by DeserializerFactoryConfig.withAdditionalKeyDeserializers(KeyDeserializers) when the argument is null. Key deserializers handle Map key conversion (e.g., String to enum keys); a null provider would cause NPEs during map deserialization, so it is rejected at registration time.

Solutions

  1. Pass a non-null KeyDeserializers instance. If you have no key deserializers, skip the call.
  2. Use SimpleKeyDeserializers as a concrete non-null container even when empty.
  3. Fix the upstream null source rather than suppressing the check.

Example fix

// before
KeyDeserializers kd = buildKeyDeserializersConditionally(); // may be null
config.withAdditionalKeyDeserializers(kd); // throws
// after
KeyDeserializers kd = buildKeyDeserializersConditionally();
if (kd != null) {
    config.withAdditionalKeyDeserializers(kd);
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate before calling
if (keyDeserializers == null) {
    throw new IllegalArgumentException("KeyDeserializers provider must not be null");
}
config.withAdditionalKeyDeserializers(keyDeserializers);

Type guard

boolean isNonNullProvider(KeyDeserializers kd) {
    return kd != null;
}

Prevention

When it happens

Trigger: Calling deserializerFactoryConfig.withAdditionalKeyDeserializers(null) directly, or via SimpleModule.set/addKeyDeserializer() internal wiring that resolves to null. Also triggered by Module.setup() implementations with conditional bugs.

Common situations: Custom modules that conditionally provide key deserializers and return null when the condition is not met. Refactoring that leaves a KeyDeserializers field uninitialized. Third-party module bugs.

Related errors


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

Appendix: source

Thrown at src/main/java/tools/jackson/databind/cfg/DeserializerFactoryConfig.java:109

    {
        if (additional == null) {
            throw new IllegalArgumentException("Cannot pass null Deserializers");
        }
        Deserializers[] all = ArrayBuilders.insertInListNoDup(_additionalDeserializers, additional);
        return new DeserializerFactoryConfig(all, _additionalKeyDeserializers, _modifiers,
                _valueInstantiators);
    }

    /**
     * Fluent/factory method used to construct a configuration object that
     * has same key deserializer providers as this instance, plus one specified
     * as argument. Additional provider will be added before existing ones,
     * meaning it has priority over existing definitions.
     */
    public DeserializerFactoryConfig withAdditionalKeyDeserializers(KeyDeserializers additional)
    {
        if (additional == null) {
            throw new IllegalArgumentException("Cannot pass null KeyDeserializers");
        }
        KeyDeserializers[] all = ArrayBuilders.insertInListNoDup(_additionalKeyDeserializers, additional);
        return new DeserializerFactoryConfig(_additionalDeserializers, all, _modifiers,
                _valueInstantiators);
    }

    /**
     * Fluent/factory method used to construct a configuration object that
     * has same configuration as this instance plus one additional
     * deserialiazer modifier. Added modifier has the highest priority (that is, it
     * gets called before any already registered modifier).
     */
    public DeserializerFactoryConfig withDeserializerModifier(ValueDeserializerModifier modifier)
    {
        if (modifier == null) {
            throw new IllegalArgumentException("Cannot pass null modifier");
        }
        ValueDeserializerModifier[] all = ArrayBuilders.insertInListNoDup(_modifiers, modifier);

View on GitHub (pinned to 87876ca5c0)