quarkusio/quarkus · error · RestClientDefinitionException
Classes used in @SseEventFilter must have a no-args construc
Error message
Classes used in @SseEventFilter must have a no-args constructor. Offending class is '${class}' What it means
Classes referenced by the `@SseEventFilter` annotation on a REST Client interface are instantiated reflectively by the runtime and therefore must have a public no-args constructor. During build, Quarkus indexes the filter class and throws RestClientDefinitionException if it lacks one.
Source
Thrown at extensions/resteasy-reactive/rest-client/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/RestClientReactiveProcessor.java:536
if (instances.isEmpty()) {
return;
}
List<String> filterClassNames = new ArrayList<>(instances.size());
for (AnnotationInstance instance : instances) {
if (instance.target().kind() != AnnotationTarget.Kind.METHOD) {
continue;
}
if (instance.value() == null) {
continue; // can't happen
}
Type filterType = instance.value().asClass();
DotName filterClassName = filterType.name();
ClassInfo filterClassInfo = index.getClassByName(filterClassName.toString());
if (filterClassInfo == null) {
log.warn("Unable to find class '" + filterType.name() + "' in index");
} else if (!filterClassInfo.hasNoArgsConstructor()) {
throw new RestClientDefinitionException(
"Classes used in @SseEventFilter must have a no-args constructor. Offending class is '"
+ filterClassName + "'");
} else {
filterClassNames.add(filterClassName.toString());
}
}
reflectiveClasses.produce(ReflectiveClassBuildItem.builder(filterClassNames.toArray(new String[0]))
.reason(getClass().getName())
.build());
}
@BuildStep
void determineRegisteredRestClients(
CombinedIndexBuildItem combinedIndexBuildItem,
RestClientsBuildTimeConfig clientsConfig,
BuildProducer<RegisteredRestClientBuildItem> producer) {
IndexView index = combinedIndexBuildItem.getIndex();
Set<DotName> seen = new HashSet<>();View on GitHub (pinned to e1c734241f)
Solutions
- Add a public no-args constructor to the filter class
- Move required state into instance fields set from the constructor-less init or static config
- Replace the filter with a new class dedicated to client-side SSE filtering
Example fix
// before
class MyFilter {
MyFilter(Logger log) { ... }
}
// after
class MyFilter {
public MyFilter() {}
MyFilter(Logger log) { ... }
} Defensive patterns
Strategy: validation
Validate before calling
// Fail fast in a unit test before building the app
SseEventFilter f = MyClient.class.getMethod("stream").getAnnotation(SseEventFilter.class);
assertThrows(null, () -> {
var ctor = f.value().getDeclaredConstructor();
});
// or at runtime:
boolean ok = java.lang.reflect.Modifier.isPublic(MyFilter.class.getDeclaredConstructor().getModifiers()); Prevention
- Always give @SseEventFilter classes a public no-args constructor
- Do not reuse server-side filters with injected constructors as client filters
- Add an ArchUnit/test asserting no-arg constructors for annotated filter classes
When it happens
Trigger: Annotating a client interface method with `@SseEventFilter(MyFilter.class)` where MyFilter only has parameterized constructors (e.g. a constructor taking a Logger or config).
Common situations: Reusing a JAX-RS server-side filter class that has dependency-injected constructors; refactoring a filter to add constructor parameters.
Related errors
- @RegisterClientContextResolver is only supported on static m
- @RegisterClientContextResolver is only supported on static m
- @ClientExceptionMapper is only supported on static methods o
- @ClientRedirectHandler is only supported on static methods o
- Only a single instance of '@ClientExceptionMapper' is allowe
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/f0491ddd298dc4a6.
Report an issue: GitHub.