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 generic argument
What it means
determineSingleGenericType extracts the single generic argument of a config property type. If the type is not a parameterized type at all (no generic argument declared), it throws IllegalArgumentException 'Type <type> which is used in class <class> must define a generic argument'. Called from the mandatory and optional value read generators for types that need one type parameter (e.g. List, Optional).
Source
Thrown at extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/ConfigurationPropertiesUtil.java:188
return false;
}
return !parameterizedType.arguments().get(0).name().toString().startsWith("java");
}
private static boolean isCollection(final Type resultType) {
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
- Add the type argument: List<String>, Optional<Duration>, etc.
- Ensure interface-based config property getters declare concrete generic return types.
- Avoid custom generic wrappers; only single-argument parameterized types are supported here.
Example fix
// before List getHosts(); // after List<String> getHosts();
Defensive patterns
Strategy: type-guard
Type guard
static boolean hasSingleGenericArg(java.lang.reflect.Type t) {
return t instanceof java.lang.reflect.ParameterizedType pt
&& pt.getActualTypeArguments().length == 1;
} Prevention
- Never use raw List/Set/Optional in @ConfigurationProperties members
- Add explicit type arguments at declaration time
- Treat rawtypes compiler warnings as errors in config modules
When it happens
Trigger: A @ConfigurationProperties field/getter uses a generic container such as List, Set, or Optional as a raw type (Kind != PARAMETERIZED_TYPE); raised while generating config population code invoked via createReadMandatoryValueAndConvertIfNeeded / createReadOptionalValueAndConvertIfNeeded.
Common situations: Raw List instead of List<String>; generics omitted on an interface getter; legacy code using raw collection 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/f21fede5bc492a95.
Report an issue: GitHub.