{"record":{"id":"4864b56336c28e1b","repo":"quarkusio/quarkus","slug":"unwrapexception-is-only-supported-on-classes-off","errorCode":null,"errorMessage":"@UnwrapException is only supported on classes. Offending target is: ${target}","messagePattern":"@UnwrapException is only supported on classes\\. Offending target is: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveScanningProcessor.java","lineNumber":159,"sourceCode":"        return List.of(new UnwrappedExceptionBuildItem(ArcUndeclaredThrowableException.class),\n                new UnwrappedExceptionBuildItem(RollbackException.class));\n    }\n\n    @BuildStep\n    public void applicationSpecificUnwrappedExceptions(CombinedIndexBuildItem combinedIndexBuildItem,\n            BuildProducer<UnwrappedExceptionBuildItem> producer) {\n        IndexView index = combinedIndexBuildItem.getIndex();\n        for (AnnotationInstance instance : index.getAnnotations(UnwrapException.class)) {\n            AnnotationValue value = instance.value();\n            AnnotationValue strategyValue = instance.value(\"strategy\");\n            ExceptionUnwrapStrategy strategy = toExceptionUnwrapStrategy(strategyValue);\n\n            if (value == null) {\n                // in this case we need to use the class where the annotation was placed as the exception to be unwrapped\n\n                AnnotationTarget target = instance.target();\n                if (target.kind() != AnnotationTarget.Kind.CLASS) {\n                    throw new IllegalStateException(\n                            \"@UnwrapException is only supported on classes. Offending target is: \" + target);\n                }\n                ClassInfo classInfo = target.asClass();\n                ClassInfo toCheck = classInfo;\n                boolean isException = false;\n                while (true) {\n                    DotName superDotName = toCheck.superName();\n                    if (EXCEPTION.equals(superDotName) || RUNTIME_EXCEPTION.equals(superDotName)) {\n                        isException = true;\n                        break;\n                    }\n                    toCheck = index.getClassByName(superDotName);\n                    if (toCheck == null) {\n                        break;\n                    }\n                }\n                if (!isException) {\n                    throw new IllegalArgumentException(","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveScanningProcessor.java#L141-L177","documentation":"@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.","triggerScenarios":"@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().","commonSituations":"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.","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"],"exampleFix":"// before\n@UnwrapException\npublic Response get() { ... }\n// after\n@UnwrapException(MyRuntimeException.class)\npublic Response get() { ... }","handlingStrategy":"validation","validationCode":"// verify @UnwrapException usage before build\nfor (AnnotatedElement el : allAnnotatedElements) {\n    UnwrapException u = el.getAnnotation(UnwrapException.class);\n    if (u != null && u.value() == UnwrapException.class /* no value */\n            && !(el instanceof Class))\n        throw new IllegalStateException(\"@UnwrapException without value must be on a class, not \" + el);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["exceptions","annotations","resteasy-reactive","quarkus","unwrap-exception"],"backgroundTag":"unwrap-exception-misuse","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}