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
- Change the `priority` attribute of one handler so values are unique
- Merge the two handlers into one method with the desired logic
- 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
- Change priority whenever copy-pasting a @ClientRedirectHandler
- Document priority conventions per project to avoid collisions
- Check parent interfaces for handlers with the same priority
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
- @ClientRedirectHandler is only supported on static methods o
- @RegisterClientContextResolver is only supported on static m
- @RegisterClientContextResolver is only supported on static m
- @ClientExceptionMapper is only supported on static methods o
- Classes used in @SseEventFilter must have a no-args construc
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/4e1568823075fdbe.
Report an issue: GitHub.