{"record":{"id":"59be2aa8aeed743b","repo":"quarkusio/quarkus","slug":"a-resource-class-cannot-be-simultaneously-annotate","errorCode":null,"errorMessage":"A resource class cannot be simultaneously annotated with '@Cache' and '@NoCache'. Offending class is '${classInfo.name()}'","messagePattern":"A resource class cannot be simultaneously annotated with '@Cache' and '@NoCache'\\. Offending class is '(.+?)'","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/scanning/CacheControlScanner.java","lineNumber":71,"sourceCode":"        }\n    }\n\n    private List<HandlerChainCustomizer> doScan(MethodInfo methodInfo, ClassInfo classInfo,\n            Map<String, Object> methodContext) {\n        AnnotationStore annotationStore = (AnnotationStore) methodContext.get(EndpointIndexer.METHOD_CONTEXT_ANNOTATION_STORE);\n        ExtendedCacheControl cacheControl = noCacheToCacheControl(annotationStore.getAnnotation(methodInfo, NO_CACHE));\n        if (cacheControl != null) {\n            if (methodInfo.annotation(CACHE) != null) {\n                throw new IllegalStateException(\n                        \"A resource method cannot be simultaneously annotated with '@Cache' and '@NoCache'. Offending method is '\"\n                                + methodInfo.name() + \"' of class '\" + methodInfo.declaringClass().name() + \"'\");\n            }\n            return cacheControlToCustomizerList(cacheControl);\n        } else {\n            cacheControl = noCacheToCacheControl(annotationStore.getAnnotation(classInfo, NO_CACHE));\n            if (cacheControl != null) {\n                if (classInfo.declaredAnnotation(CACHE) != null) {\n                    throw new IllegalStateException(\n                            \"A resource class cannot be simultaneously annotated with '@Cache' and '@NoCache'. Offending class is '\"\n                                    + classInfo.name() + \"'\");\n                }\n                return cacheControlToCustomizerList(cacheControl);\n            }\n        }\n\n        cacheControl = cacheToCacheControl(methodInfo.annotation(CACHE));\n        if (cacheControl != null) {\n            return cacheControlToCustomizerList(cacheControl);\n        } else {\n            cacheControl = cacheToCacheControl(classInfo.declaredAnnotation(CACHE));\n            if (cacheControl != null) {\n                return cacheControlToCustomizerList(cacheControl);\n            }\n        }\n\n        return Collections.emptyList();","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/scanning/CacheControlScanner.java#L53-L89","documentation":"RESTEasy Reactive lets you declare cache-control behavior on resource classes via @Cache and @NoCache annotations. These are mutually exclusive, so during the build-time scan (CacheControlScanner.doScan) a class declaring both is rejected with this IllegalStateException to fail the deployment fast rather than produce ambiguous caching behavior.","triggerScenarios":"Annotating the same JAX-RS resource class with both @Cache (or @Cache with variants) and @NoCache, typically by accident when annotations accumulate on a class over time or are added at both class and subclass levels that get merged.","commonSituations":"Copy-pasting annotation blocks from another resource; a base class annotated @NoCache while a subclass adds @Cache; IDE auto-imports adding the wrong annotation alongside the intended one.","solutions":["Remove either @Cache or @NoCache from the offending class (the class name is given in the message).","If inheritance is involved, keep the cache-control annotation on exactly one level of the class hierarchy.","Decide the intended caching semantics: @Cache for cacheable responses, @NoCache to force revalidation, and annotate only with that one."],"exampleFix":"// before\n@Cache(maxAge = 3600)\n@NoCache\npublic class MyResource { ... }\n// after\n@Cache(maxAge = 3600)\npublic class MyResource { ... }","handlingStrategy":"validation","validationCode":"if (resourceClass.isAnnotationPresent(Cache.class) && resourceClass.isAnnotationPresent(NoCache.class)) {\n    throw new IllegalStateException(resourceClass + \" has both @Cache and @NoCache\");\n}","typeGuard":"boolean hasConflictingCacheAnnotations(ClassInfo classInfo) {\n    return classInfo.declaredAnnotation(\"jakarta.ws.rs.Cache\") != null\n        && classInfo.declaredAnnotation(\"jakarta.ws.rs.NoCache\") != null;\n}","tryCatchPattern":"try {\n    scanner.doScan(...);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"'@Cache' and '@NoCache'\")) {\n        log.error(\"Remove one of the conflicting annotations: \" + e.getMessage());\n    }\n    throw e;\n}","preventionTips":["Annotate cache-control at exactly one hierarchy level per resource class.","Review imports after copy-pasting annotation blocks.","Add an ArchUnit or build-time check asserting no class declares both annotations.","Search the codebase for classes annotated with @NoCache before adding @Cache anywhere in the hierarchy."],"tags":["quarkus","resteasy-reactive","jax-rs","annotation-conflict","build-time"],"backgroundTag":"conflicting-annotations","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"}