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
- Use a supported key type: String, Integer, Long, or another primitive wrapper
- Change Map to List<ValuePair> or a dedicated POJO if structured keys are needed
- 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
- Use Map<String, T> for query-parameter maps
- Avoid custom classes as map keys in query binding
- Model complex keys as separate POJO parameters instead
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
- Cannot get QueryReader for: " + type
- Uni must be used with type parameter (e.g. Uni<String>).
- RuntimeException(e)
- A generic type is not allowed here; try creating a subclass
- Unsupported wildcard type: ${wildcard}
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/8a5726979222f010.
Report an issue: GitHub.