quarkusio/quarkus · error · IllegalArgumentException
Map parameter types must have String keys. Offending method
Error message
Map parameter types must have String keys. Offending method is: {jandexMethod} What it means
A client method accepts a Map parameter (e.g. for query or matrix parameters). Quarkus must iterate its keys to build the URI, and it requires keys to be String so they can be encoded directly. A Map with non-String key types is rejected at build time.
Source
Thrown at extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java:3256
String paramName,
ResultHandle paramHandle,
Type type,
IndexView index,
// this client or containing client if we're in a subresource
ResultHandle client,
ResultHandle genericType,
ResultHandle paramAnnotations,
String webTargetParamMethod,
String separator) {
AssignableResultHandle result = methodCreator.createVariable(WebTarget.class);
BranchResult isParamNull = methodCreator.ifNull(paramHandle);
BytecodeCreator notNullParam = isParamNull.falseBranch();
if (isMap(type, index)) {
var resolvesTypes = resolveMapTypes(type, jandexMethod);
var keyType = resolvesTypes.getKey();
if (!ResteasyReactiveDotNames.STRING.equals(keyType.name())) {
throw new IllegalArgumentException(
"Map parameter types must have String keys. Offending method is: " + jandexMethod);
}
notNullParam.assign(result, webTarget);
// Loop through the keys
ResultHandle keySet = notNullParam.invokeInterfaceMethod(ofMethod(Map.class, "keySet", Set.class),
paramHandle);
ResultHandle keysIterator = notNullParam.invokeInterfaceMethod(
ofMethod(Set.class, "iterator", Iterator.class), keySet);
BytecodeCreator loopCreator = notNullParam.whileLoop(c -> iteratorHasNext(c, keysIterator)).block();
ResultHandle key = loopCreator.invokeInterfaceMethod(
ofMethod(Iterator.class, "next", Object.class), keysIterator);
// get the value and convert
ResultHandle value = loopCreator.invokeInterfaceMethod(ofMethod(Map.class, "get", Object.class, Object.class),
paramHandle, key);
var valueType = resolvesTypes.getValue();
String componentType = valueType.name().toString();
ResultHandle paramArray;
if (isCollection(valueType, index)) {View on GitHub (pinned to e1c734241f)
Solutions
- Change the Map key type parameter to String: Map<String, String>
- Convert non-String keys to Strings before calling and pass Map<String, ...>
- If keys are enum/objects, pre-map them to their String names
Example fix
// before
@GET
@Path("search")
List<Item> search(Map<Integer, String> filters);
// after
@GET
@Path("search")
List<Item> search(Map<String, String> filters); Defensive patterns
Strategy: type-guard
Validate before calling
static void requireStringKeys(Map<?, ?> params, String where) {
for (Object k : params.keySet()) {
if (!(k instanceof String)) {
throw new IllegalArgumentException(
where + ": Map keys must be String, got " + k.getClass().getName());
}
}
} Type guard
static boolean isStringKeyedMap(Object o) {
if (!(o instanceof Map<?, ?> m)) return false;
return m.keySet().stream().allMatch(k -> k instanceof String);
} Prevention
- Always declare client Map params as Map<String, String> (or Map<String, List<String>>)
- Convert enum/object keys to String at the call site
- Add an interface-level unit test that calls each method with sample params
When it happens
Trigger: Declaring `void get(Map<Integer, String> params)` (or any non-String key) as a query-param style Map parameter on a @RegisterRestClient interface method.
Common situations: Reusing an internal Map with Long/enum keys as a parameter bag; generic Map<K,V> where K resolves to a non-String type after type-variable resolution.
Related errors
- multipart responses can only be mapped to non-generic classe
- Type variable %s of %s could not be resolved.
- parameterized type %s can not be inherited from by %s (or a
- Raw Map parameter types are not supported. Offending method
- Raw MultivaluedMap parameter types are not supported. Offend
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/f331b5a4fdedf388.
Report an issue: GitHub.