quarkusio/quarkus · error · RuntimeException
io.quarkus.oidc.client.OidcClientFilter annotation can be ap
Error message
io.quarkus.oidc.client.OidcClientFilter annotation can be applied either on class %s or its methods
What it means
During OIDC client filter build-step processing, a REST client interface was found where the @OidcClientFilter annotation appears both on the class and on at least one of its methods. Quarkus cannot decide unambiguously whether to register the filter per class or per method, so the build fails with this RuntimeException.
Source
Thrown at extensions/oidc-client/deployment/src/main/java/io/quarkus/oidc/client/deployment/OidcClientFilterDeploymentHelper.java:251
.filter(ai -> ai.target().kind() == AnnotationTarget.Kind.CLASS)
.map(ai -> ai.target().asClass())
.toList());
result.addAll(index
.getAnnotations(registerProvidersClass).stream()
.filter(ai -> ai.value() != null)
.filter(ai -> registersDeclaringClass(ai, declaringClassName))
.filter(ai -> ai.target().kind() == AnnotationTarget.Kind.CLASS)
.map(ai -> ai.target().asClass())
.toList());
}
}
}
}
return result;
}
private static void throwBothMethodAndClassAnnotated(AnnotationInstance instance) {
throw new RuntimeException(OidcClientFilter.class.getName() + " annotation can be applied either on class "
+ getTargetRestClient(instance) + " or its methods");
}
private static boolean registersDeclaringClass(AnnotationInstance ai, DotName declaringClassName) {
return Arrays.stream(ai.value().asNestedArray())
.anyMatch(nestedAi -> nestedAi.value().asClass().name().equals(declaringClassName));
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Remove @OidcClientFilter from the method(s) and keep it only on the class to apply to all methods.
- Remove @OidcClientFilter from the class and keep it only on the specific method(s) that need it.
- Split the REST client into two interfaces: one class-annotated and one method-annotated, if both behaviors are genuinely needed.
Example fix
// before
@OidcClientFilter
public interface MyClient {
@OidcClientFilter
@GET String get();
}
// after
@OidcClientFilter
public interface MyClient {
@GET String get();
} Defensive patterns
Strategy: validation
Validate before calling
boolean classAnnotated = Arrays.stream(MyClient.class.getAnnotations()).anyMatch(a -> a instanceof OidcClientFilter);
boolean methodAnnotated = Arrays.stream(MyClient.class.getMethods()).anyMatch(m -> m.isAnnotationPresent(OidcClientFilter.class));
if (classAnnotated && methodAnnotated) throw new IllegalStateException("@OidcClientFilter on both class and method"); Prevention
- Pick one annotation level: class for all methods, method-level for selective use.
- Review REST client interfaces after copy-paste edits.
- Run a build-step/architectural test that scans client interfaces for duplicate annotation targets.
When it happens
Trigger: A REST client interface annotated with @OidcClientFilter at class level AND with @OidcClientFilter on one of its methods, encountered while getOrCreateNamedTokensProducerFor processes annotation instances.
Common situations: Copy-paste adding the annotation to both the interface and an individual method; combining a global class-level filter with an attempt to customize a single method.
Related errors
- The configuration ${clazz} is missing the @ConfigRoot annota
- Annotation instance ${annotationInstance} does not match ann
- Unknown value of annotation member ${name}
- Method ${method} not implemented
- 'quarkus-narayana-lra' can only work if 'quarkus-rest-client
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/6ce5d3d90b6915cc.
Report an issue: GitHub.