{"record":{"id":"8a5726979222f010","repo":"quarkusio/quarkus","slug":"illegal-key-type-for-map","errorCode":null,"errorMessage":"Illegal key type for map","messagePattern":"Illegal key type for map","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"extensions/funqy/funqy-server-common/runtime/src/main/java/io/quarkus/funqy/runtime/query/QueryMapReader.java","lineNumber":31,"sourceCode":" * Value can be any primitive, primitive object, string, or bean style class\n *\n */\nclass QueryMapReader extends BaseObjectReader implements BaseObjectReader.ValueSetter {\n    private Function<String, Object> keyExtractor;\n    private Function<String, Object> valueExtractor;\n    private QueryPropertySetter setter;\n\n    public QueryMapReader(Type genericType, QueryObjectMapper mapper) {\n        if (genericType == null) {\n            keyExtractor = mapper.extractor(String.class);\n            valueExtractor = mapper.extractor(String.class);\n            return;\n        }\n        if (genericType instanceof ParameterizedType) {\n            Type keyType = ((ParameterizedType) genericType).getActualTypeArguments()[0];\n            keyExtractor = mapper.extractor(keyType);\n            if (keyType == null)\n                throw new RuntimeException(\"Illegal key type for map\");\n            Type valueType = ((ParameterizedType) genericType).getActualTypeArguments()[1];\n            if (valueType != null) {\n                Class<Object> rawType = Reflections.getRawType(valueType);\n                valueExtractor = mapper.extractor(valueType);\n                if (valueExtractor == null) {\n                    setter = mapper.setterFor(rawType, valueType);\n                }\n            } else {\n                valueExtractor = mapper.extractor(String.class);\n            }\n        } else {\n            keyExtractor = mapper.extractor(String.class);\n            Class<Object> rawType = Reflections.getRawType(genericType);\n            valueExtractor = mapper.extractor(rawType);\n            if (valueExtractor == null) {\n                setter = mapper.setterFor(rawType, genericType);\n            }\n        }","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/funqy/funqy-server-common/runtime/src/main/java/io/quarkus/funqy/runtime/query/QueryMapReader.java#L13-L49","documentation":"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.","triggerScenarios":"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.","commonSituations":"Using complex POJOs or custom classes as map keys in query-param binding; missing generic parameters on the Map declaration in some refactors.","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"],"exampleFix":"// before\n@Funq public void f(Map<UserId, String> map) { ... }\n// after\n@Funq public void f(Map<String, String> map) { ... }","handlingStrategy":"validation","validationCode":"// Check map key type is supported before binding\nstatic void assertSupportedMapKey(Type mapType) {\n    if (mapType instanceof ParameterizedType) {\n        Type key = ((ParameterizedType) mapType).getActualTypeArguments()[0];\n        Set<Class<?>> supported = Set.of(String.class, Integer.class, Long.class,\n            int.class, long.class, Object.class);\n        // reject unsupported custom key classes\n    }\n}","typeGuard":"static <K,V> boolean hasSupportedKey(Map<K,V> m) {\n    return m == null || m.isEmpty()\n        || m.keySet().iterator().next() instanceof String;\n}","tryCatchPattern":"try {\n    new QueryMapReader(type, mapper);\n} catch (RuntimeException e) {\n    if (e.getMessage().equals(\"Illegal key type for map\"))\n        log.error(\"Use String/primitive map keys for query binding\");\n    throw e;\n}","preventionTips":["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"],"tags":["quarkus","funqy","query-binding","generics"],"backgroundTag":"unsupported-map-key-type","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}