quarkusio/quarkus · error · RestClientDefinitionException
Method ${declaringClass}#${methodName} has an unsupported re
Error message
Method ${declaringClass}#${methodName} has an unsupported return type for ${annotationName}. Only String and String[] return types are supported What it means
The method providing a header/query param value must return String or String[]. Any other return type (Integer, List, Optional, etc.) is rejected at build time because the generated code repacks the result into a List of Strings and cannot convert arbitrary types.
Source
Thrown at extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/MicroProfileRestClientEnricher.java:474
methodCallCreator.load(paramName));
} else {
throw new RestClientDefinitionException(
annotationName + " method " + declaringClass + "#" + methodName
+ " has too many parameters, at most one parameter, param name, expected");
}
}
Type returnType = paramValueMethod.returnType();
ResultHandle valuesList;
if (isStringArray(returnType)) {
// repack array to list
valuesList = methodCallCreator.invokeStaticMethod(ARRAYS_AS_LIST, paramValue);
} else if (isString(returnType)) {
valuesList = methodCallCreator.newInstance(MethodDescriptor.ofConstructor(ArrayList.class));
methodCallCreator.invokeInterfaceMethod(LIST_ADD_METHOD, valuesList, paramValue);
} else {
throw new RestClientDefinitionException("Method " + declaringClass.toString() + "#" + methodName
+ " has an unsupported return type for " + annotationName + ". " +
"Only String and String[] return types are supported");
}
paramAdder.accept(methodCallCreator, valuesList);
if (!required) {
CatchBlockCreator catchBlock = tryBlock.addCatch(Exception.class);
ResultHandle log = catchBlock.invokeStaticMethod(
MethodDescriptor.ofMethod(Logger.class, "getLogger", Logger.class, String.class),
catchBlock.load(declaringClass.name().toString()));
String errorMessage = String.format(
"Invoking param generation method '%s' for '%s' on method '%s#%s' failed",
methodName, paramName, declaringClass.name(), declaringMethod.name());
catchBlock.invokeVirtualMethod(
MethodDescriptor.ofMethod(Logger.class, "warn", void.class, Object.class, Throwable.class),
log,
catchBlock.load(errorMessage), catchBlock.getCaughtException());View on GitHub (pinned to e1c734241f)
Solutions
- Change the return type to String
- Use String[] if multiple values are needed
- Convert non-String values inside the method before returning
Example fix
// before
static List<String> tags() { return List.of("a","b"); }
// after
static String[] tags() { return new String[]{"a","b"}; } Defensive patterns
Strategy: type-guard
Validate before calling
boolean validReturnType(Method m) {
Class<?> r = m.getReturnType();
return r == String.class || r == String[].class;
} Type guard
static boolean isSupportedValueMethod(Method m) {
Class<?> r = m.getReturnType();
return r == String.class || r == String[].class;
} Prevention
- Only return String or String[] from value providers
- Convert collections inside the method (e.g. String.join)
- Add a unit test asserting the return type before wiring the annotation
When it happens
Trigger: @ClientQueryParam valueFrom method returning int, Optional<String>, List<String>, or a custom type; the enricher hits the else branch and throws.
Common situations: Developers assume wrapper/collection types are converted automatically, or refactor a method's return type from String after adding caching/Optional.
Related errors
- Offending class is '${className}'
- 'quarkus-narayana-lra' can only work if 'quarkus-rest-client
- io.quarkus.oidc.client.OidcClientFilter annotation can be ap
- %s does not implement %s
- Not possible to define the scope %s for the REST client %s
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/7610284563a663f5.
Report an issue: GitHub.