quarkusio/quarkus · error · IllegalStateException

A resource class cannot be simultaneously annotated with '@C

Error message

A resource class cannot be simultaneously annotated with '@Cache' and '@NoCache'. Offending class is '${classInfo.name()}'

What it means

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.

Source

Thrown at independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/scanning/CacheControlScanner.java:71

        }
    }

    private List<HandlerChainCustomizer> doScan(MethodInfo methodInfo, ClassInfo classInfo,
            Map<String, Object> methodContext) {
        AnnotationStore annotationStore = (AnnotationStore) methodContext.get(EndpointIndexer.METHOD_CONTEXT_ANNOTATION_STORE);
        ExtendedCacheControl cacheControl = noCacheToCacheControl(annotationStore.getAnnotation(methodInfo, NO_CACHE));
        if (cacheControl != null) {
            if (methodInfo.annotation(CACHE) != null) {
                throw new IllegalStateException(
                        "A resource method cannot be simultaneously annotated with '@Cache' and '@NoCache'. Offending method is '"
                                + methodInfo.name() + "' of class '" + methodInfo.declaringClass().name() + "'");
            }
            return cacheControlToCustomizerList(cacheControl);
        } else {
            cacheControl = noCacheToCacheControl(annotationStore.getAnnotation(classInfo, NO_CACHE));
            if (cacheControl != null) {
                if (classInfo.declaredAnnotation(CACHE) != null) {
                    throw new IllegalStateException(
                            "A resource class cannot be simultaneously annotated with '@Cache' and '@NoCache'. Offending class is '"
                                    + classInfo.name() + "'");
                }
                return cacheControlToCustomizerList(cacheControl);
            }
        }

        cacheControl = cacheToCacheControl(methodInfo.annotation(CACHE));
        if (cacheControl != null) {
            return cacheControlToCustomizerList(cacheControl);
        } else {
            cacheControl = cacheToCacheControl(classInfo.declaredAnnotation(CACHE));
            if (cacheControl != null) {
                return cacheControlToCustomizerList(cacheControl);
            }
        }

        return Collections.emptyList();

View on GitHub (pinned to e1c734241f)

Solutions

  1. Remove either @Cache or @NoCache from the offending class (the class name is given in the message).
  2. If inheritance is involved, keep the cache-control annotation on exactly one level of the class hierarchy.
  3. Decide the intended caching semantics: @Cache for cacheable responses, @NoCache to force revalidation, and annotate only with that one.

Example fix

// before
@Cache(maxAge = 3600)
@NoCache
public class MyResource { ... }
// after
@Cache(maxAge = 3600)
public class MyResource { ... }
Defensive patterns

Strategy: validation

Validate before calling

if (resourceClass.isAnnotationPresent(Cache.class) && resourceClass.isAnnotationPresent(NoCache.class)) {
    throw new IllegalStateException(resourceClass + " has both @Cache and @NoCache");
}

Type guard

boolean hasConflictingCacheAnnotations(ClassInfo classInfo) {
    return classInfo.declaredAnnotation("jakarta.ws.rs.Cache") != null
        && classInfo.declaredAnnotation("jakarta.ws.rs.NoCache") != null;
}

Try / catch

try {
    scanner.doScan(...);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("'@Cache' and '@NoCache'")) {
        log.error("Remove one of the conflicting annotations: " + e.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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