quarkusio/quarkus · error · IllegalArgumentException
Unsupported param type: " + paramType
Error message
Unsupported param type: " + paramType
What it means
During build-time bytecode generation, the Quarkus reactive-routes extension generates route handler code that converts String request parameters into the method's declared parameter types (Integer, Long, Float, Double, Character, etc.). If a route method declares a parameter whose type has no conversion recipe, the generated bytecode factory throws IllegalArgumentException at build time.
Source
Thrown at extensions/reactive-routes/deployment/src/main/java/io/quarkus/vertx/web/deployment/ReactiveRoutesProcessor.java:1736
tc.body(b2 -> {
if (paramType.name().equals(DotName.BOOLEAN_CLASS_NAME)) {
b2.set(param, b2.invokeStatic(Methods.BOOLEAN_VALUE_OF, param));
} else if (paramType.name().equals(DotName.BYTE_CLASS_NAME)) {
b2.set(param, b2.invokeStatic(Methods.BYTE_VALUE_OF, param));
} else if (paramType.name().equals(DotName.SHORT_CLASS_NAME)) {
b2.set(param, b2.invokeStatic(Methods.SHORT_VALUE_OF, param));
} else if (paramType.name().equals(DotName.INTEGER_CLASS_NAME)) {
b2.set(param, b2.invokeStatic(Methods.INTEGER_VALUE_OF, param));
} else if (paramType.name().equals(DotName.LONG_CLASS_NAME)) {
b2.set(param, b2.invokeStatic(Methods.LONG_VALUE_OF, param));
} else if (paramType.name().equals(DotName.FLOAT_CLASS_NAME)) {
b2.set(param, b2.invokeStatic(Methods.FLOAT_VALUE_OF, param));
} else if (paramType.name().equals(DotName.DOUBLE_CLASS_NAME)) {
b2.set(param, b2.invokeStatic(Methods.DOUBLE_VALUE_OF, param));
} else if (paramType.name().equals(DotName.CHARACTER_CLASS_NAME)) {
b2.set(param, b2.invokeStatic(Methods.CHARACTER_VALUE_OF, b2.withString(param).charAt(0)));
} else {
throw new IllegalArgumentException("Unsupported param type: " + paramType);
}
});
tc.catch_(Throwable.class, "e", (b2, e) -> {
b2.throw_(b2.new_(ConstructorDesc.of(IllegalArgumentException.class, String.class, Throwable.class),
Const.of("Error converting parameter #" + methodParam.position() + " of method "
+ methodParam.method().declaringClass() + "." + methodParam.method().name() + "()"),
e));
});
});
});
}
@FunctionalInterface
interface ValueProvider {
Expr get(MethodParameterInfo methodParam, Set<AnnotationInstance> annotations, Var routingContext,
BlockCreator bc, BuildProducer<ReflectiveHierarchyBuildItem> reflectiveHierarchy);
View on GitHub (pinned to e1c734241f)
Solutions
- Change the route method parameter to a supported type (String, Integer, Long, Float, Double, Character, boolean/Boolean primitives) and convert manually inside the method.
- Accept the parameter as String and parse it in the method body (e.g. LocalDate.parse(param)).
- Register a custom converter or wrap the value in a class the extension supports; check the reactive-routes documentation for the current list of supported param types.
Example fix
// before
@Route(path = "/by-date", methods = HttpMethod.GET)
public Uni<String> byDate(@Param("d") LocalDate d) { ... }
// after
@Route(path = "/by-date", methods = HttpMethod.GET)
public Uni<String> byDate(@Param("d") String d) {
LocalDate date = LocalDate.parse(d);
...
} Defensive patterns
Strategy: validation
Validate before calling
private static final Set<String> SUPPORTED = Set.of("java.lang.String","java.lang.Integer","java.lang.Long","java.lang.Float","java.lang.Double","java.lang.Character","java.lang.Boolean");
void checkParamTypes(Class<?>[] types) {
for (Class<?> t : types)
if (!SUPPORTED.contains(t.getName()))
throw new IllegalArgumentException("Unsupported route param type: " + t);
} Prevention
- Restrict route method parameters to String and boxed primitives
- Parse complex types (LocalDate, UUID) inside the method body
- Add an ArchUnit test asserting route param types
- Check reactive-routes docs for the supported param type list before adding new endpoints
When it happens
Trigger: Declaring a @Route-annotated method with a @Param (query/path parameter) whose type is not one of the supported boxed primitives (e.g. a LocalDate, UUID, BigDecimal, or custom POJO parameter).
Common situations: Migrating an app to reactive routes and reusing DTO types for parameters; assuming automatic conversion for date/time or numeric wrapper types like BigInteger; copying a controller from Spring where richer parameter binding exists.
Related errors
- Unknown type
- Route filter method must return void [method: %s, bean: %s]
- Route filter method must accept exactly one parameter of typ
- Failed to open path tree with root %s
- Dev services for ${request.getName()} requires a startable s
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/c65c097e16bb061c.
Report an issue: GitHub.