quarkusio/quarkus · error · IllegalArgumentException
A generic type is not allowed here; try creating a subclass
Error message
A generic type is not allowed here; try creating a subclass with concrete type arguments instead: %s
What it means
BuildItem's constructor enforces that every concrete build item is a non-generic, final class. It inspects getClass() at instantiation time and throws this IllegalArgumentException if the runtime class still declares type parameters. The Quarkus build system requires build items to be unique concrete types so they can be keyed in the dependency graph; a generic BuildItem<Multimap<String,String>> cannot be identified unambiguously.
Source
Thrown at core/builder/src/main/java/io/quarkus/builder/item/BuildItem.java:17
package io.quarkus.builder.item;
import java.lang.reflect.Modifier;
/**
* A build item which can be produced or consumed. Any item
* which implements {@link AutoCloseable} will be automatically closed when the build
* is completed, unless it is explicitly marked as a final build result in which case closure is
* the responsibility of whomever invoked the build execution.
* <p>
* Resources should be fine-grained as possible, ideally describing only one aspect of the build process.
*/
public abstract class BuildItem {
BuildItem() {
final Class<? extends BuildItem> clazz = getClass();
if (clazz.getTypeParameters().length != 0) {
throw new IllegalArgumentException(
"A generic type is not allowed here; try creating a subclass with concrete type arguments instead: "
+ getClass());
}
if (!Modifier.isFinal(clazz.getModifiers())) {
throw new IllegalArgumentException("Build item class must be leaf (final) types: " + getClass());
}
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Create a concrete final subclass with fixed type arguments, e.g. `public final class StringMapItem extends BuildItem<Map<String,String>>` — wait, instead define `final class MyItem extends BuildItem` with fields, and use that.
- Replace the generic type parameter with explicit fields on a final class (e.g. `final class LocaleMapBuildItem extends BuildItem { final Map<String,Locale> map; }`).
- If instantiating an anonymous generic subclass, convert it to a named final class so getClass() has no type parameters.
- Rebuild after changes — the check runs at construction, so any path constructing the generic class must be migrated.
Example fix
// before
class MyItem<T> extends BuildItem {
final T payload;
MyItem(T payload) { this.payload = payload; }
}
new MyItem<Map<String,String>>(map);
// after
public final class MyMapItem extends BuildItem {
final Map<String,String> payload;
public MyMapItem(Map<String,String> payload) { this.payload = payload; }
}
new MyMapItem(map); Defensive patterns
Strategy: type-guard
Validate before calling
static <T extends BuildItem> T validateNonGeneric(Class<? extends T> clazz) {
if (clazz.getTypeParameters().length != 0) {
throw new IllegalArgumentException(
clazz + " is generic; define a concrete final subclass with fixed fields instead");
}
return null; // validation-only helper; real instance is constructed after this passes
} Type guard
static boolean isConcreteBuildItem(Class<?> clazz) {
return BuildItem.class.isAssignableFrom(clazz)
&& clazz.getTypeParameters().length == 0
&& !clazz.isAnonymousClass();
} Try / catch
try {
BuildItem item = new MyMapItem(map);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("A generic type is not allowed here")) {
throw new IllegalStateException("Refactor " + e.getMessage() + " into a final concrete BuildItem subclass", e);
}
throw e;
} Prevention
- Never declare type parameters on BuildItem subclasses
- Carry generic payloads in explicit typed fields of a concrete final item
- Avoid anonymous subclassing of build items
- Write an architecture/unit test asserting every BuildItem subclass is final and non-generic
When it happens
Trigger: Declaring `class MyItem<T> extends BuildItem` and instantiating it (possibly via an anonymous or subclass form) instead of creating a concrete final subclass with fixed type arguments; instantiating a generic item directly with `new MyItem<Something>()`; using an anonymous class of a generic item that retains type parameters.
Common situations: Developers porting code that used generics for payload flexibility; refactoring where a generic base item was previously instantiated directly; anonymous subclassing `new BuildItem<Map<K,V>>(){}` patterns that keep type parameters at runtime.
Related errors
- Build item class must be leaf (final) types: %s
- Cannot construct empty build items
- A build step must be a non-static method: %s
- Unsupported wildcard type: ${wildcard}
- Can not add converter ${converter.name()} that is not parame
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/a8f007f9ecb445c2.
Report an issue: GitHub.