quarkusio/quarkus · error · IllegalStateException

Only a single instance of '@ClientRedirectHandler' with the

Error message

Only a single instance of '@ClientRedirectHandler' with the same priority is allowed per REST Client interface. Offending class is '${class}'

What it means

A REST Client interface may not declare two `@ClientRedirectHandler` methods with the same priority. Quarkus keeps a priority-ordered map of generated redirect handlers per interface and throws IllegalStateException on a priority collision, since ordering would be ambiguous.

Source

Thrown at extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/RestClientReactiveProcessor.java:903

        }
        return result;
    }

    private Map<String, GeneratedClassResult> populateClientRedirectHandlerFromAnnotations(
            Gizmo gizmo,
            BuildProducer<ReflectiveClassBuildItem> reflectiveClasses, IndexView index) {

        var result = new HashMap<String, GeneratedClassResult>();
        ClientRedirectHandler clientHandler = new ClientRedirectHandler(gizmo);
        for (AnnotationInstance instance : index.getAnnotations(CLIENT_REDIRECT_HANDLER)) {
            GeneratedClassResult classResult = clientHandler.generateResponseExceptionMapper(instance);
            if (classResult == null) {
                continue;
            }

            GeneratedClassResult existing = result.get(classResult.interfaceName);
            if (existing != null && existing.priority == classResult.priority) {
                throw new IllegalStateException("Only a single instance of '" + CLIENT_REDIRECT_HANDLER
                        + "' with the same priority is allowed per REST Client interface. "
                        + "Offending class is '" + classResult.interfaceName + "'");
            } else if (existing == null || existing.priority < classResult.priority) {
                result.put(classResult.interfaceName, classResult);
                reflectiveClasses.produce(ReflectiveClassBuildItem.builder(classResult.generatedClassName)
                        .reason(getClass().getName())
                        .build());
            }
        }
        return result;
    }

    private Map<String, GeneratedClassResult> populateClientProviderFromAnnotations(
            AnnotationToRegisterIntoClientContextBuildItem annotationBuildItem,
            Gizmo gizmo,
            BuildProducer<ReflectiveClassBuildItem> reflectiveClasses, IndexView index) {

        var result = new HashMap<String, GeneratedClassResult>();

View on GitHub (pinned to e1c734241f)

Solutions

  1. Change the `priority` attribute of one handler so values are unique
  2. Merge the two handlers into one method with the desired logic
  3. Remove the redundant handler

Example fix

// before
@ClientRedirectHandler(priority = 100) Response h1(...)
@ClientRedirectHandler(priority = 100) Response h2(...)
// after
@ClientRedirectHandler(priority = 100) Response h1(...)
@ClientRedirectHandler(priority = 200) Response h2(...)
Defensive patterns

Strategy: validation

Validate before calling

// Ensure priorities are unique per interface
Map<Integer, Long> byPriority = Arrays.stream(MyClient.class.getMethods())
    .filter(m -> m.isAnnotationPresent(ClientRedirectHandler.class))
    .map(m -> m.getAnnotation(ClientRedirectHandler.class).priority())
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
if (byPriority.values().stream().anyMatch(c -> c > 1)) throw new IllegalStateException("Duplicate handler priority");

Prevention

When it happens

Trigger: Two `@ClientRedirectHandler` static methods on the same client interface whose `priority()` attribute values are identical.

Common situations: Copy-pasting a redirect handler and forgetting to change the priority; two handlers inherited from different parent interfaces that happen to share a priority.

Related errors


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