quarkusio/quarkus · error · IllegalStateException

@ClientRedirectHandler is only supported on static methods o

Error message

@ClientRedirectHandler is only supported on static methods of REST Client interfaces that take 'jakarta.ws.rs.core.Response' as a single parameter and return 'java.net.URI'. Offending instance is '${className}#${methodName}'

What it means

@ClientRedirectHandler annotates a static method that decides a redirect URI from a failed Response. Quarkus enforces the exact contract: static method, single jakarta.ws.rs.core.Response parameter, java.net.URI return type. This IllegalStateException fails the build when the annotated method violates it.

Source

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

                    boolean returnsUri = URI.class.isAssignableFrom(
                            Class.forName(returnTypeClassName, false, Thread.currentThread().getContextClassLoader()));
                    if (returnsUri) {
                        isValid = true;
                    }
                } catch (ClassNotFoundException ignored) {

                }
            }
        }
        if (!isValid) {
            String message = DotNames.CLIENT_REDIRECT_HANDLER
                    + " is only supported on static methods of REST Client interfaces that take 'jakarta.ws.rs.core.Response'"
                    + " as a single parameter and return 'java.net.URI'.";
            if (targetMethod != null) {
                message += " Offending instance is '" + targetMethod.declaringClass().name().toString() + "#"
                        + targetMethod.name() + "'";
            }
            throw new IllegalStateException(message);
        }

        StringBuilder sigBuilder = new StringBuilder();
        sigBuilder.append(targetMethod.name()).append("_").append(targetMethod.returnType().name().toString());
        for (Type i : targetMethod.parameterTypes()) {
            sigBuilder.append(i.name().toString());
        }

        int priority = Priorities.USER;
        AnnotationValue priorityAnnotationValue = instance.value("priority");
        if (priorityAnnotationValue != null) {
            priority = priorityAnnotationValue.asInt();
        }

        ClassInfo restClientInterfaceClassInfo = targetMethod.declaringClass();
        String generatedClassName = restClientInterfaceClassInfo.name().toString() + "_" + targetMethod.name() + "_"
                + "ResponseRedirectHandler" + "_" + HashUtil.sha1(sigBuilder.toString());
        final MethodInfo target = targetMethod;

View on GitHub (pinned to e1c734241f)

Solutions

  1. Change the method to accept exactly one jakarta.ws.rs.core.Response and return java.net.URI
  2. Make the method static and keep it in the REST client interface
  3. Convert String URLs with URI.create(...) before returning

Example fix

// before
@ClientRedirectHandler
static String redirect(Response r) { return "/login"; }
// after
@ClientRedirectHandler
static java.net.URI redirect(Response r) {
    return java.net.URI.create("/login");
}
Defensive patterns

Strategy: validation

Validate before calling

static boolean validRedirectHandler(Method m) {
    return Modifier.isStatic(m.getModifiers())
        && m.getParameterCount() == 1
        && m.getParameterTypes()[0] == jakarta.ws.rs.core.Response.class
        && m.getReturnType() == java.net.URI.class;
}

Try / catch

try {
    handler.generateResponseExceptionMapper(classResult, instance);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("ClientRedirectHandler")) { /* fix to (Response)->URI */ }
    throw e;
}

Prevention

When it happens

Trigger: @ClientRedirectHandler method that is non-static, has no or extra parameters, does not take Response, or returns String/void/other instead of java.net.URI.

Common situations: Returning a String URL instead of URI; adding a second parameter for context; copy-pasting an @ClientExceptionMapper method and changing only the annotation.

Related errors


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