quarkusio/quarkus · error · IllegalStateException

Can only be called from a @PreMatch filter

Error message

Can only be called from a @PreMatch filter

What it means

Per JAX-RS, ContainerRequestContext.setRequestUri and setMethod may only be invoked from @PreMatch ContainerRequestFilters (before resource routing). ContainerRequestContextImpl.assertPreMatch checks the isPreMatch flag and throws IllegalStateException otherwise, because changing URI/method after routing would invalidate the match.

Source

Thrown at independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/ContainerRequestContextImpl.java:89

    @Override
    public Request getRequest() {
        return quarkusRestContext.getRequest();
    }

    @Override
    public String getMethod() {
        return quarkusRestContext.getMethod();
    }

    @Override
    public void setMethod(String method) {
        assertPreMatch();
        quarkusRestContext.setMethod(method);
    }

    public void assertPreMatch() {
        if (!isPreMatch()) {
            throw new IllegalStateException("Can only be called from a @PreMatch filter");
        }
    }

    public void assertNotResponse() {
        if (isResponse()) {
            throw new IllegalStateException("Cannot be called from response filter");
        }
    }

    @Override
    public MultivaluedMap<String, String> getHeaders() {
        return quarkusRestContext.getHttpHeaders().getMutableHeaders();
    }

    @Override
    public String getHeaderString(String name) {
        return quarkusRestContext.getHttpHeaders().getHeaderString(name);
    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Annotate the ContainerRequestFilter class with @PreMatch so it runs before routing
  2. Move URI/method rewriting logic into the pre-match filter
  3. If rewriting after match is required, throw a redirection or use a different mechanism (e.g. abortWith a redirect Response)
  4. Verify no duplicate filter registration changes its phase

Example fix

// before
@Provider
public class RewriteFilter implements ContainerRequestFilter {
    public void filter(ContainerRequestContext ctx) {
        ctx.setRequestUri(new URI("/new")); // fails
    }
}
// after
@PreMatch
@Provider
public class RewriteFilter implements ContainerRequestFilter {
    public void filter(ContainerRequestContext ctx) {
        ctx.setRequestUri(new URI("/new"));
    }
}
Defensive patterns

Strategy: validation

Validate before calling

if (!isPreMatchPhase(filter)) {
    throw new IllegalStateException("setRequestUri/setMethod require @PreMatch");
}

Type guard

static boolean isPreMatchFilter(Class<?> f) {
    return f.isAnnotationPresent(jakarta.ws.rs.container.PreMatch.class);
}

Try / catch

try { ctx.setRequestUri(newUri); } catch (IllegalStateException e) { if (e.getMessage().contains("@PreMatch")) { /* move logic to pre-match filter or redirect */ } throw e; }

Prevention

When it happens

Trigger: Calling requestContext.setRequestUri(...) or setMethod(...) from a filter registered without @PreMatch (i.e. a post-match filter running after routing), or from a response filter.

Common situations: Adding @Priority only and assuming pre-match semantics; rewriting URLs for legacy redirects in a named/@NameBinding filter that lost @PreMatch; framework upgrades changing filter phase classification.

Related errors


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