quarkusio/quarkus · error · IllegalStateException
Only a single instance of '@ClientExceptionMapper' is allowe
Error message
Only a single instance of '@ClientExceptionMapper' is allowed per REST Client interface. Offending class is '${class}' What it means
A REST Client interface may declare at most one method annotated with `@ClientExceptionMapper` (including inherited ones). Quarkus generates one exception-mapper class per interface during build and throws IllegalStateException when a second instance targets the same interface.
Source
Thrown at extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/RestClientReactiveProcessor.java:878
BuildProducer<ExecutionModelAnnotationsAllowedBuildItem> executionModelAnnotationsAllowedProducer) {
executionModelAnnotationsAllowedProducer.produce(new ExecutionModelAnnotationsAllowedBuildItem(
new Predicate<>() {
@Override
public boolean test(MethodInfo methodInfo) {
return methodInfo.hasDeclaredAnnotation(CLIENT_EXCEPTION_MAPPER);
}
}));
var result = new HashMap<String, GeneratedClassResult>();
ClientExceptionMapperHandler clientExceptionMapperHandler = new ClientExceptionMapperHandler(gizmo);
for (AnnotationInstance instance : index.getAnnotations(CLIENT_EXCEPTION_MAPPER)) {
GeneratedClassResult classResult = clientExceptionMapperHandler.generateResponseExceptionMapper(instance);
if (classResult == null) {
continue;
}
if (result.containsKey(classResult.interfaceName)) {
throw new IllegalStateException("Only a single instance of '" + CLIENT_EXCEPTION_MAPPER
+ "' is allowed per REST Client interface. Offending class is '" + classResult.interfaceName + "'");
}
result.put(classResult.interfaceName, classResult);
reflectiveClassesProducer.produce(ReflectiveClassBuildItem.builder(classResult.generatedClassName)
.reason(getClass().getName())
.build());
}
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);View on GitHub (pinned to e1c734241f)
Solutions
- Keep only one `@ClientExceptionMapper` method per interface and merge the logic
- Move shared mapping logic into a helper method called by the single mapper
- Check parent interfaces for inherited mappers and remove duplicates
Example fix
// before
@ClientExceptionMapper Response map1(Response r) {...}
@ClientExceptionMapper Response map2(Response r) {...}
// after
@ClientExceptionMapper Response map(Response r) {
if (r.getStatus()==404) return notFound();
return map2Logic(r);
} Defensive patterns
Strategy: validation
Validate before calling
// Verify at build/test time only one mapper exists per interface
long count = Arrays.stream(MyClient.class.getMethods())
.filter(m -> m.isAnnotationPresent(ClientExceptionMapper.class))
.count();
if (count > 1) throw new IllegalStateException("Duplicate @ClientExceptionMapper on " + MyClient.class); Prevention
- Grep for @ClientExceptionMapper across interface hierarchies before adding a new one
- Keep mapper logic in one method per interface
- Watch for mappers inherited from shared parent interfaces
When it happens
Trigger: Two `@ClientExceptionMapper` static methods defined on the same client interface (possibly via interface inheritance or a shared parent interface).
Common situations: Adding a new mapper while an inherited default one already exists; multiple interfaces extending a common interface each defining their own mapper and then both applied to one client.
Related errors
- @ClientExceptionMapper is only supported on static methods o
- @RegisterClientContextResolver is only supported on static m
- @RegisterClientContextResolver is only supported on static m
- Unsupported parameter type used in @ClientExceptionMapper. S
- @ClientRedirectHandler is only supported on static methods o
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/c4fdf6a837e94465.
Report an issue: GitHub.