quarkusio/quarkus · error · IllegalStateException

You can only have a single class annotated with @ControllerA

Error message

You can only have a single class annotated with @ControllerAdvice

What it means

Quarkus's Spring Web support builds a single, global ExceptionMapper set from one @ControllerAdvice class (matching Spring's ability to have one precedence-winning advice, but implemented more strictly). If more than one class is annotated @ControllerAdvice, the build fails because the processor cannot pick a winner.

Source

Thrown at extensions/spring-web/core/deployment/src/main/java/io/quarkus/spring/web/deployment/SpringWebProcessor.java:261

        }

        // allow access to HttpHeaders from Arc.container()
        if (!isResteasyClassic) {
            unremovableBeanProducer.produce(
                    UnremovableBeanBuildItem.beanClassNames("org.jboss.resteasy.reactive.server.injection.ContextProducers",
                            HttpHeaders.class.getName()));
        }
    }

    private AnnotationInstance getSingleControllerAdviceInstance(IndexView index) {
        Collection<AnnotationInstance> controllerAdviceInstances = index.getAnnotations(REST_CONTROLLER_ADVICE);

        if (controllerAdviceInstances.isEmpty()) {
            return null;
        }

        if (controllerAdviceInstances.size() > 1) {
            throw new IllegalStateException("You can only have a single class annotated with @ControllerAdvice");
        }

        return controllerAdviceInstances.iterator().next();
    }

}

View on GitHub (pinned to e1c734241f)

Solutions

  1. Merge the @ExceptionHandler methods of all @ControllerAdvice classes into a single class.
  2. Remove @ControllerAdvice from redundant classes (plain classes don't need it).
  3. Use @Priority-aware JAX-RS ExceptionMappers directly for fine-grained per-exception handling instead.

Example fix

// before
@ControllerAdvice class GlobalAdvice { ... }
@ControllerAdvice class PaymentAdvice { ... }

// after: merge into one
@ControllerAdvice class GlobalAdvice {
  @ExceptionHandler(PaymentException.class) ...
  @ExceptionHandler(IllegalArgumentException.class) ...
}
Defensive patterns

Strategy: validation

Validate before calling

// enforce a single advice class, e.g. an ArchUnit/test check:
// assertThat(classesAnnotatedWith(ControllerAdvice.class)).hasSize(1);

Prevention

When it happens

Trigger: Two or more classes annotated with @ControllerAdvice in the application, detected during the controllerAdviceSupport build step.

Common situations: Merging modules that each brought their own advice class; adding a new advice without deleting the demo/template one; splitting exception handling across teams.

Related errors


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