quarkusio/quarkus · error · IllegalStateException
@UnwrapException is only supported on classes. Offending tar
Error message
@UnwrapException is only supported on classes. Offending target is: ${target} What it means
@UnwrapException marks exception types whose cause should be surfaced instead of the wrapper. When used without a value, it must be placed on a class, so Quarkus can walk the class hierarchy to determine what is unwrapped. If the annotation target is a method, field, or parameter, deployment fails with this IllegalStateException.
Source
Thrown at extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveScanningProcessor.java:159
return List.of(new UnwrappedExceptionBuildItem(ArcUndeclaredThrowableException.class),
new UnwrappedExceptionBuildItem(RollbackException.class));
}
@BuildStep
public void applicationSpecificUnwrappedExceptions(CombinedIndexBuildItem combinedIndexBuildItem,
BuildProducer<UnwrappedExceptionBuildItem> producer) {
IndexView index = combinedIndexBuildItem.getIndex();
for (AnnotationInstance instance : index.getAnnotations(UnwrapException.class)) {
AnnotationValue value = instance.value();
AnnotationValue strategyValue = instance.value("strategy");
ExceptionUnwrapStrategy strategy = toExceptionUnwrapStrategy(strategyValue);
if (value == null) {
// in this case we need to use the class where the annotation was placed as the exception to be unwrapped
AnnotationTarget target = instance.target();
if (target.kind() != AnnotationTarget.Kind.CLASS) {
throw new IllegalStateException(
"@UnwrapException is only supported on classes. Offending target is: " + target);
}
ClassInfo classInfo = target.asClass();
ClassInfo toCheck = classInfo;
boolean isException = false;
while (true) {
DotName superDotName = toCheck.superName();
if (EXCEPTION.equals(superDotName) || RUNTIME_EXCEPTION.equals(superDotName)) {
isException = true;
break;
}
toCheck = index.getClassByName(superDotName);
if (toCheck == null) {
break;
}
}
if (!isException) {
throw new IllegalArgumentException(View on GitHub (pinned to e1c734241f)
Solutions
- Move @UnwrapException from the method/field to the resource class or the exception class itself
- If you want method-level behavior, instead handle it with an ExceptionMapper or annotate the exception class with @UnwrapException
- Provide an explicit value: @UnwrapException(SomeException.class) where the annotation is declared
Example fix
// before
@UnwrapException
public Response get() { ... }
// after
@UnwrapException(MyRuntimeException.class)
public Response get() { ... } Defensive patterns
Strategy: validation
Validate before calling
// verify @UnwrapException usage before build
for (AnnotatedElement el : allAnnotatedElements) {
UnwrapException u = el.getAnnotation(UnwrapException.class);
if (u != null && u.value() == UnwrapException.class /* no value */
&& !(el instanceof Class))
throw new IllegalStateException("@UnwrapException without value must be on a class, not " + el);
} Prevention
- Only place @UnwrapException on classes (exception classes or resource classes)
- Use @UnwrapException(SomeException.class) where method/element-level marking is tempting
- Prefer ExceptionMapper for method-scoped exception handling
When it happens
Trigger: @UnwrapException is placed on a non-class element (typically a resource method) with no explicit value attribute, and the scan of application-level @UnwrapException instances processes that target in applicationSpecificUnwrappedExceptions().
Common situations: Annotating a method expecting it to unwrap exceptions thrown by it (a common misconception); IDE auto-import adding the annotation at method level; migrating from another framework's semantics.
Related errors
- Using @UnwrapException without a value is only supported on
- Cannot have more than one of @PathParam, @QueryParam, @Heade
- No annotations found on fields at '%s'. Annotations like `@Q
- A resource method cannot be simultaneously annotated with '@
- Value not set for ${param}
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/4864b56336c28e1b.
Report an issue: GitHub.