{"record":{"id":"40d0b48889483a89","repo":"quarkusio/quarkus","slug":"can-only-be-called-from-a-prematch-filter","errorCode":null,"errorMessage":"Can only be called from a @PreMatch filter","messagePattern":"Can only be called from a @PreMatch filter","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/ContainerRequestContextImpl.java","lineNumber":89,"sourceCode":"    @Override\n    public Request getRequest() {\n        return quarkusRestContext.getRequest();\n    }\n\n    @Override\n    public String getMethod() {\n        return quarkusRestContext.getMethod();\n    }\n\n    @Override\n    public void setMethod(String method) {\n        assertPreMatch();\n        quarkusRestContext.setMethod(method);\n    }\n\n    public void assertPreMatch() {\n        if (!isPreMatch()) {\n            throw new IllegalStateException(\"Can only be called from a @PreMatch filter\");\n        }\n    }\n\n    public void assertNotResponse() {\n        if (isResponse()) {\n            throw new IllegalStateException(\"Cannot be called from response filter\");\n        }\n    }\n\n    @Override\n    public MultivaluedMap<String, String> getHeaders() {\n        return quarkusRestContext.getHttpHeaders().getMutableHeaders();\n    }\n\n    @Override\n    public String getHeaderString(String name) {\n        return quarkusRestContext.getHttpHeaders().getHeaderString(name);\n    }","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/jaxrs/ContainerRequestContextImpl.java#L71-L107","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Annotate the ContainerRequestFilter class with @PreMatch so it runs before routing","Move URI/method rewriting logic into the pre-match filter","If rewriting after match is required, throw a redirection or use a different mechanism (e.g. abortWith a redirect Response)","Verify no duplicate filter registration changes its phase"],"exampleFix":"// before\n@Provider\npublic class RewriteFilter implements ContainerRequestFilter {\n    public void filter(ContainerRequestContext ctx) {\n        ctx.setRequestUri(new URI(\"/new\")); // fails\n    }\n}\n// after\n@PreMatch\n@Provider\npublic class RewriteFilter implements ContainerRequestFilter {\n    public void filter(ContainerRequestContext ctx) {\n        ctx.setRequestUri(new URI(\"/new\"));\n    }\n}","handlingStrategy":"validation","validationCode":"if (!isPreMatchPhase(filter)) {\n    throw new IllegalStateException(\"setRequestUri/setMethod require @PreMatch\");\n}","typeGuard":"static boolean isPreMatchFilter(Class<?> f) {\n    return f.isAnnotationPresent(jakarta.ws.rs.container.PreMatch.class);\n}","tryCatchPattern":"try { ctx.setRequestUri(newUri); } catch (IllegalStateException e) { if (e.getMessage().contains(\"@PreMatch\")) { /* move logic to pre-match filter or redirect */ } throw e; }","preventionTips":["Annotate any filter that rewrites URI or method with @PreMatch","Keep post-match filters read-only for routing info","Review filter phase after adding @NameBinding or @Priority"],"tags":["resteasy-reactive","jaxrs-filter","prematch","request-context"],"backgroundTag":"filter-phase-violation","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}