quarkusio/quarkus · error · IllegalArgumentException
Type variable %s of %s could not be resolved.
Error message
Type variable %s of %s could not be resolved.
What it means
While resolving the type arguments of a multipart response's parameterized return type, a nested type variable (e.g. the T in Wrapper<T>) could not be found in the ownerIdentifierTypeLookupMap built from the declaration. The generator cannot synthesize a GenericType without a concrete type, so it throws an IllegalArgumentException including the unresolved identifier and the declaration site.
Source
Thrown at extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java:1493
private Type resolveType(Type type,
Map<String, Type> ownerIdentifierTypeLookupMap, Declaration declaration) {
if (type.kind() == PARAMETERIZED_TYPE) {
ParameterizedType parameterizedReturnType = type.asParameterizedType();
ParameterizedType.Builder methodReturnTypeBuilder = ParameterizedType.builder(type.name());
for (int i = 0; i < parameterizedReturnType.arguments().size(); i++) {
Type paramReturnTypeArg = parameterizedReturnType.arguments().get(i);
Type resolvedType;
if (paramReturnTypeArg.kind() == TYPE_VARIABLE) {
// method returns another subresource, and one of the arguments is a type variable e.g. Wrapper<T>
resolvedType = ownerIdentifierTypeLookupMap.get(paramReturnTypeArg.asTypeVariable().identifier());
if (resolvedType == null) {
String declarationSite = declaration.toString();
if (declaration.kind() == AnnotationTarget.Kind.METHOD) {
declarationSite = "method %s in class %s".formatted(declaration,
declaration.asMethod().declaringClass());
}
throw new IllegalArgumentException(
"Type variable %s of %s could not be resolved."
.formatted(paramReturnTypeArg.asTypeVariable().identifier(), declarationSite));
}
} else if (paramReturnTypeArg.kind() == PARAMETERIZED_TYPE) {
// parameterized type contains another parameterized type with either a type variable e.g. Wrapper<List<T>> or without, e.g. Wrapper<List<String>>
resolvedType = resolveType(paramReturnTypeArg, ownerIdentifierTypeLookupMap, declaration);
} else {
resolvedType = paramReturnTypeArg;
}
methodReturnTypeBuilder.addArgument(resolvedType);
}
// rewrite parameterized type to reflect the resolved type variable
// i.e. Wrapper<String> instead of Wrapper<V>
return methodReturnTypeBuilder.build();
} else if (type.kind() == TYPE_VARIABLE) {
TypeVariable typeVariable = type.asTypeVariable();View on GitHub (pinned to e1c734241f)
Solutions
- Bind the type variable: make the declaring class/interface parameterized with a concrete type (interface MyClient extends GenericClient<MultipartBody>)
- Change the multipart method return to a fully concrete type
- Verify that all type variables used in the return type appear in the method or declaring class signature
Example fix
// before
class MyClient implements GenericClient<T> { T get(); } // raw T
// after
class MyClient implements GenericClient<MultipartBody> { MultipartBody get(); } Defensive patterns
Strategy: validation
Validate before calling
static void assertBoundGenerics(Class<?> clientItf) { for (var m : clientItf.getMethods()) { for (var a : ((ParameterizedType) m.getGenericReturnType() instanceof ParameterizedType pt ? pt.getActualTypeArguments() : new Type[0])) { if (a instanceof TypeVariable) throw new IllegalStateException("Unbound type var " + a + " in " + m); } } } Type guard
boolean allTypeArgsConcrete(Type t) { return !(t instanceof TypeVariable) && (!(t instanceof ParameterizedType pt) || Arrays.stream(pt.getActualTypeArguments()).allMatch(a -> a instanceof Class || (a instanceof ParameterizedType p && allTypeArgsConcrete(p)))); } Try / catch
try { client.fetch(); } catch (IllegalArgumentException e) { if (e.getMessage().contains("could not be resolved")) { log.error("Bind the type variable named in the message"); } throw e; } Prevention
- Parameterize generic base interfaces with concrete types
- Never extend a generic client interface raw
- Keep type variables bound at the client interface level
- Read the exception's declaration site to locate the unbound variable
When it happens
Trigger: A client method returns e.g. Wrapper<T> or Result<T, E> where a nested type argument is a type variable that no enclosing declaration binds — e.g. the type variable comes from an unparameterized superclass or interface rather than the method itself.
Common situations: Generic base interfaces (Repository<T> with getClient returning T) extended raw; missing explicit type argument in an extends clause; mixing generic helper classes into multipart responses.
Related errors
- multipart responses can only be mapped to non-generic classe
- Raw Map parameter types are not supported. Offending method
- Raw MultivaluedMap parameter types are not supported. Offend
- Unsupported Map type '{type.name()}'. Offending method is: {
- Unsupported wildcard type: ${wildcard}
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/1fc5c94064fe119b.
Report an issue: GitHub.