quarkusio/quarkus · error · IllegalStateException

Only a single instance of '${annotation}' is allowed per RES

Error message

Only a single instance of '${annotation}' 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 a given context-resolver-style annotation (supplied by RestClientReactiveResolverBuildItem, e.g. `@ClientQueryParam` resolver style handlers). Quarkus generates one class per annotation per interface and throws IllegalStateException when it encounters a second instance for the same interface.

Source

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

        }
        return result;
    }

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

        var result = new HashMap<String, GeneratedClassResult>();
        ClientContextResolverHandler handler = new ClientContextResolverHandler(annotationBuildItem.getAnnotation(),
                annotationBuildItem.getExpectedReturnType(), gizmo);
        for (AnnotationInstance instance : index.getAnnotations(annotationBuildItem.getAnnotation())) {
            GeneratedClassResult classResult = handler.generateContextResolver(instance);
            if (classResult == null) {
                continue;
            }
            if (result.containsKey(classResult.interfaceName)) {
                throw new IllegalStateException("Only a single instance of '" + annotationBuildItem.getAnnotation()
                        + "' is allowed per REST Client interface. Offending class is '" + classResult.interfaceName + "'");
            }
            result.put(classResult.interfaceName, classResult);
            reflectiveClasses.produce(ReflectiveClassBuildItem.builder(classResult.generatedClassName)
                    .reason(getClass().getName())
                    .build());
        }
        return result;
    }

    private int getAnnotatedPriority(IndexView index, String className, int defaultPriority) {
        ClassInfo providerClass = index.getClassByName(DotName.createSimple(className));
        int priority = defaultPriority;
        if (providerClass == null) {
            log.warnv("Unindexed provider class {0}. The priority of the provider will be set to {1}. ", className,
                    defaultPriority);
        } else {
            AnnotationInstance priorityAnnoOnProvider = providerClass.declaredAnnotation(ResteasyReactiveDotNames.PRIORITY);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Keep a single method with the annotation on the interface and merge logic
  2. Remove the duplicate from the parent interface or exclude inheritance
  3. Move shared behavior into a plain helper method

Example fix

// before
@MyResolver String resolve1(UriInfo uri)
@MyResolver String resolve2(UriInfo uri)
// after
@MyResolver String resolve(UriInfo uri) {
    return cond ? resolve1Logic(uri) : resolve2Logic(uri);
}
Defensive patterns

Strategy: validation

Validate before calling

// Assert at most one resolver-annotated method per client interface
long count = Arrays.stream(MyClient.class.getMethods())
    .filter(m -> m.isAnnotationPresent(MyResolver.class))
    .count();
if (count > 1) throw new IllegalStateException("Multiple @MyResolver methods on " + MyClient.class);

Prevention

When it happens

Trigger: Two methods annotated with the same resolver annotation (e.g. two `@ClientExceptionMapper`-style generated handlers from a registered annotation build item) on the same interface, including via inheritance.

Common situations: Inheriting a resolver method from a parent interface while also declaring one directly; copy-paste duplication within one interface.

Related errors


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