quarkusio/quarkus · error · RuntimeException
Suspend method '${targetMethod.name()} of class '${targetMet
Error message
Suspend method '${targetMethod.name()} of class '${targetMethod.declaringClass().name()}' cannot be used as a request filter as it does not declare 'void', 'Response', 'RestResponse' as its return type. What it means
CustomFilterGenerator's generateRequestFilterForSuspendedMethod handles Kotlin suspend request filter methods by unwrapping their Continuation return type. After unwrapping, the underlying return type must be void, Response, or RestResponse; anything else throws this RuntimeException and fails the Quarkus build.
Source
Thrown at independent-projects/resteasy-reactive/server/processor/src/main/java/org/jboss/resteasy/reactive/server/processor/generation/filters/CustomFilterGenerator.java:110
checkModifiers(targetMethod, ResteasyReactiveServerDotNames.SERVER_REQUEST_FILTER);
if (KotlinUtils.isSuspendMethod(targetMethod)) {
return generateRequestFilterForSuspendedMethod(targetMethod, classOutput, isOptionalFilter.test(targetMethod));
}
return generateStandardRequestFilter(targetMethod, classOutput, isOptionalFilter.test(targetMethod));
}
private String generateRequestFilterForSuspendedMethod(MethodInfo targetMethod, ClassOutput classOutput,
boolean checkForOptionalBean) {
DotName returnDotName = determineReturnDotNameOfSuspendMethod(targetMethod);
ReturnType returnType;
if (returnDotName.equals(VOID)) {
returnType = ReturnType.VOID;
} else if (returnDotName.equals(RESPONSE)) {
returnType = ReturnType.RESPONSE;
} else if (returnDotName.equals(REST_RESPONSE)) {
returnType = ReturnType.REST_RESPONSE;
} else {
throw new RuntimeException("Suspend method '" + targetMethod.name() + " of class '"
+ targetMethod.declaringClass().name()
+ "' cannot be used as a request filter as it does not declare 'void', 'Response', 'RestResponse' as its return type.");
}
String generatedClassName = getGeneratedClassName(targetMethod, ResteasyReactiveServerDotNames.SERVER_REQUEST_FILTER);
ClassInfo declaringClass = targetMethod.declaringClass();
DotName declaringClassName = declaringClass.name();
try (ClassCreator cc = ClassCreator.builder().classOutput(classOutput)
.className(generatedClassName)
.superClass(ABSTRACT_SUSPENDED_REQ_FILTER)
.build()) {
FieldDescriptor delegateField = generateConstructorAndDelegateField(cc, declaringClass,
ABSTRACT_SUSPENDED_REQ_FILTER, additionalBeanAnnotations, checkForOptionalBean);
// generate the implementation of the 'doFilter' method
MethodCreator doFilterMethod = cc.getMethodCreator("doFilter", Object.class.getName(),
ResteasyReactiveContainerRequestContext.class.getName(), ResteasyReactiveDotNames.CONTINUATION.toString());
ResultHandle delegate = doFilterMethod.readInstanceField(delegateField, doFilterMethod.getThis());View on GitHub (pinned to e1c734241f)
Solutions
- Change the suspend filter to return Unit (void) and mutate the ContainerRequestContext or call context.abortWith(...) instead
- Return Response or RestResponse from the suspend filter for early termination
- If you want to accept/abort without a response, use the non-suspend filter returning void or the documented Boolean-based pattern
- Remove @ServerRequestFilter if the method is not a filter
Example fix
// before (Kotlin)
@ServerRequestFilter
suspend fun filter(ctx: ContainerRequestContext): String { ... }
// after
@ServerRequestFilter
suspend fun filter(ctx: ContainerRequestContext) {
ctx.abortWith(Response.status(401).build())
} Defensive patterns
Strategy: validation
Validate before calling
// Kotlin: check suspend request filter return before build
val m = clazz.declaredMethods.first { it.isAnnotationPresent(ServerRequestFilter::class.java) }
val allowed = setOf(Void.TYPE, Response::class.java, RestResponse::class.java)
require(m.returnType in allowed) { "Suspend request filter must return Unit, Response, or RestResponse: $m" }
Type guard
fun isValidSuspendRequestFilter(m: Method): Boolean =
m.returnType == Void.TYPE || m.returnType == Response::class.java || m.returnType == RestResponse::class.java
Prevention
- In Kotlin suspend filters, return Unit and mutate/abort the request context instead of returning values
- Return Response or RestResponse only for early-abort suspend filters
- Keep filter signatures minimal and copy them from the Quarkus documentation examples
When it happens
Trigger: A Kotlin suspend fun used as a @ServerRequestFilter whose Continuation-wrapped return type is something other than void/Unit, Response, or RestResponse — e.g. returning String, Int, or a custom type.
Common situations: Kotlin developers writing suspend filters that return a value instead of mutating the request context, or returning Boolean (the dedicated @ServerRequestFilter filterOnly variant should be used instead).
Related errors
- ReturnType: '${returnType}' is not supported, in method ${ta
- Parameter '${parameterName}' of method '${targetMethod.name(
- Suspend method '${targetMethod.name()} of class '${targetMet
- Offending class is '${className}'
- The combination of '@${annotationName}' and '@ServerRequestF
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/5aa14229f1b24971.
Report an issue: GitHub.