quarkusio/quarkus · error · IllegalStateException

@Compressed and @Uncompressed cannot be both declared on…

Error message

@Compressed and @Uncompressed cannot be both declared on resource method %s declared on %s

What it means

CompressionScanner inspects JAX-RS resource methods at build time to compute their HTTP compression setting from the Quarkus @Compressed and @Uncompressed annotations, which are mutually exclusive. If a single resource method is annotated with both, the scanner cannot decide the behavior and throws this IllegalStateException during deployment.

Solutions

  1. Remove one of the two annotations from the resource method, keeping only @Compressed or @Uncompressed.
  2. If both were inherited via meta-annotations, split the custom annotation into two or drop one layer.
  3. Let the method inherit class/global compression config (quarkus.resteasy reactive compression settings) by removing both annotations.

Example fix

// before
@Compressed
@Uncompressed // conflict
@GET
public String get() { ... }

// after
@Compressed
@GET
public String get() { ... }
Defensive patterns

Strategy: validation

Validate before calling

static void assertNotBoth(Method m) {
    boolean compressed = m.isAnnotationPresent(Compressed.class);
    boolean uncompressed = m.isAnnotationPresent(Uncompressed.class);
    if (compressed && uncompressed)
        throw new IllegalStateException("@Compressed and @Uncompressed cannot both be on " + m);
}

Try / catch

// Fails during Quarkus augmentation, not at runtime; guard in a unit test:
try {
    runAugmentation();
} catch (IllegalStateException e) {
    if (e.getMessage().contains("cannot be both declared")) {
        log.error("Remove one of @Compressed/@Uncompressed: " + e.getMessage());
    }
}

Prevention

When it happens

Trigger: Annotating the same resource method (in a class scanned as a REST endpoint) with both io.quarkus.resteasy.reactive.Compressed and Uncompressed, triggering RESTEasy Reactive server deployment scanning.

Common situations: Toggling compression during development and forgetting to remove the other annotation; inheriting/composing annotations from a meta-annotated custom annotation that carries both; merge conflicts adding both annotations.

Related errors


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

Appendix: source

Thrown at extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/CompressionScanner.java:48

    public CompressionScanner(VertxHttpBuildTimeConfig httpBuildTimeConfig) {
        this.httpBuildTimeConfig = httpBuildTimeConfig;
    }

    @Override
    public List<HandlerChainCustomizer> scan(MethodInfo method, ClassInfo actualEndpointClass,
            Map<String, Object> methodContext) {
        if (!httpBuildTimeConfig.enableCompression()) {
            return Collections.emptyList();
        }

        AnnotationStore annotationStore = (AnnotationStore) methodContext.get(EndpointIndexer.METHOD_CONTEXT_ANNOTATION_STORE);
        HttpCompression compression = HttpCompression.UNDEFINED;
        if (annotationStore.hasAnnotation(method, COMPRESSED)) {
            compression = HttpCompression.ON;
        }
        if (annotationStore.hasAnnotation(method, UNCOMPRESSED)) {
            if (compression == HttpCompression.ON) {
                throw new IllegalStateException(
                        String.format(
                                "@Compressed and @Uncompressed cannot be both declared on resource method %s declared on %s",
                                method, actualEndpointClass));
            } else {
                compression = HttpCompression.OFF;
            }
        }
        if (compression == HttpCompression.OFF) {
            // No action is needed because the "Content-Encoding: identity" header is set for every request if compression is enabled
            return Collections.emptyList();
        }
        ResteasyReactiveCompressionHandler handler = new ResteasyReactiveCompressionHandler(
                // Avoid using Set.copyOf() here as it creates SetN<E> with unstable iteration order.
                // This leads to bytecode being unstable across builds. Prefer using HashSet wrapped
                // in Collections.unmodifiableSet() instead.
                Collections.unmodifiableSet(
                        new HashSet<>(httpBuildTimeConfig.compressMediaTypes().orElse(Collections.emptyList()))));
        handler.setCompression(compression);

View on GitHub (pinned to e1c734241f)