quarkusio/quarkus · error · RuntimeException

Illegal key type for map

Error message

Illegal key type for map

What it means

When a Funqy query function parameter is a Map, QueryMapReader extracts a key extractor from the map's generic key type. If the key extractor cannot be created (mapper.extractor returned null), the reader throws 'Illegal key type for map'. Note the code checks keyType == null after calling extractor — the failure occurs when the key type has no supported extractor.

Source

Thrown at extensions/funqy/funqy-server-common/runtime/src/main/java/io/quarkus/funqy/runtime/query/QueryMapReader.java:31

 * Value can be any primitive, primitive object, string, or bean style class
 *
 */
class QueryMapReader extends BaseObjectReader implements BaseObjectReader.ValueSetter {
    private Function<String, Object> keyExtractor;
    private Function<String, Object> valueExtractor;
    private QueryPropertySetter setter;

    public QueryMapReader(Type genericType, QueryObjectMapper mapper) {
        if (genericType == null) {
            keyExtractor = mapper.extractor(String.class);
            valueExtractor = mapper.extractor(String.class);
            return;
        }
        if (genericType instanceof ParameterizedType) {
            Type keyType = ((ParameterizedType) genericType).getActualTypeArguments()[0];
            keyExtractor = mapper.extractor(keyType);
            if (keyType == null)
                throw new RuntimeException("Illegal key type for map");
            Type valueType = ((ParameterizedType) genericType).getActualTypeArguments()[1];
            if (valueType != null) {
                Class<Object> rawType = Reflections.getRawType(valueType);
                valueExtractor = mapper.extractor(valueType);
                if (valueExtractor == null) {
                    setter = mapper.setterFor(rawType, valueType);
                }
            } else {
                valueExtractor = mapper.extractor(String.class);
            }
        } else {
            keyExtractor = mapper.extractor(String.class);
            Class<Object> rawType = Reflections.getRawType(genericType);
            valueExtractor = mapper.extractor(rawType);
            if (valueExtractor == null) {
                setter = mapper.setterFor(rawType, genericType);
            }
        }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Use a supported key type: String, Integer, Long, or another primitive wrapper
  2. Change Map to List<ValuePair> or a dedicated POJO if structured keys are needed
  3. Provide a custom extractor via QueryObjectMapper extension if the framework allows it

Example fix

// before
@Funq public void f(Map<UserId, String> map) { ... }
// after
@Funq public void f(Map<String, String> map) { ... }
Defensive patterns

Strategy: validation

Validate before calling

// Check map key type is supported before binding
static void assertSupportedMapKey(Type mapType) {
    if (mapType instanceof ParameterizedType) {
        Type key = ((ParameterizedType) mapType).getActualTypeArguments()[0];
        Set<Class<?>> supported = Set.of(String.class, Integer.class, Long.class,
            int.class, long.class, Object.class);
        // reject unsupported custom key classes
    }
}

Type guard

static <K,V> boolean hasSupportedKey(Map<K,V> m) {
    return m == null || m.isEmpty()
        || m.keySet().iterator().next() instanceof String;
}

Try / catch

try {
    new QueryMapReader(type, mapper);
} catch (RuntimeException e) {
    if (e.getMessage().equals("Illegal key type for map"))
        log.error("Use String/primitive map keys for query binding");
    throw e;
}

Prevention

When it happens

Trigger: Declaring a function parameter like Map<MyCustomKey, String> where the key type is not a supported simple type (String, primitives, enums etc.) in query binding.

Common situations: Using complex POJOs or custom classes as map keys in query-param binding; missing generic parameters on the Map declaration in some refactors.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/8a5726979222f010. Report an issue: GitHub.