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

  1. Move @UnwrapException from the method/field to the resource class or the exception class itself
  2. If you want method-level behavior, instead handle it with an ExceptionMapper or annotate the exception class with @UnwrapException
  3. 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

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


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/4864b56336c28e1b. Report an issue: GitHub.