quarkusio/quarkus · error · IllegalArgumentException
Type + type.name().toString() + which is used in class +
Error message
Type + type.name().toString() + which is used in class + declaringClass + must define a single generic argument
What it means
Companion check in determineSingleGenericType: the type IS parameterized but declares more than one generic argument. Types used in this position must have exactly one type argument, otherwise IllegalArgumentException '... must define a single generic argument' is thrown.
Source
Thrown at extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/ConfigurationPropertiesUtil.java:194
return DotNames.COLLECTION.equals(resultType.name()) ||
DotNames.LIST.equals(resultType.name()) ||
DotNames.SET.equals(resultType.name());
}
private static boolean isMap(final Type resultType) {
return DotNames.MAP.equals(resultType.name()) ||
DotNames.HASH_MAP.equals(resultType.name());
}
static Type determineSingleGenericType(Type type, DotName declaringClass) {
if (!(type.kind() == Type.Kind.PARAMETERIZED_TYPE)) {
throw new IllegalArgumentException("Type " + type.name().toString() + " which is used in class " + declaringClass
+ " must define a generic argument");
}
ParameterizedType parameterizedType = type.asParameterizedType();
if (parameterizedType.arguments().size() != 1) {
throw new IllegalArgumentException("Type " + type.name().toString() + " which is used in class " + declaringClass
+ " must define a single generic argument");
}
return type.asParameterizedType().arguments().get(0);
}
static void registerImplicitConverter(Type type, BuildProducer<ReflectiveClassBuildItem> reflectiveClasses) {
// We need to register for reflection in case an implicit converter is required.
if (!MicroProfileConfigProcessor.isHandledByProducers(type)) {
if (type.kind() != Type.Kind.ARRAY) {
reflectiveClasses
.produce(ReflectiveClassBuildItem.builder(type.name().toString()).methods().build());
}
}
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Use single-argument types (List<T>, Optional<T>, Set<T>) for such properties; handle Maps via the dedicated Map path with parameterized Map<K, V>.
- Split multi-argument types into simpler properties.
- Review which container type the getter returns and align it with the supported set.
Example fix
// before Pair<String, Integer> getRange(); // after List<Integer> getRange(); // or a supported single-arg type
Defensive patterns
Strategy: type-guard
Type guard
static boolean isSingleArgContainer(java.lang.reflect.Type t) {
return t instanceof java.lang.reflect.ParameterizedType pt
&& pt.getActualTypeArguments().length == 1;
} Prevention
- Use List<T>/Optional<T>/Set<T> (one type argument) for these properties
- Model key-value config with Map<String, V> via the dedicated Map path instead
- Avoid custom multi-argument generic types in config members
When it happens
Trigger: A @ConfigurationProperties property type like Map<String, String> (two type arguments) or Pair<A, B> is passed to determineSingleGenericType from the value-read generators, which expect single-argument types (List, Optional, Set).
Common situations: Using Map-typed properties through the path intended for List/Optional types; custom two-parameter generic types as property types.
Related errors
- Unsupported wildcard type: ${wildcard}
- Invalid type:
- multipart responses can only be mapped to non-generic classe
- Type variable %s of %s could not be resolved.
- Raw Map parameter types are not supported. Offending method
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/c8ad43ba1075abcf.
Report an issue: GitHub.