quarkusio/quarkus · error · IllegalStateException
Response already committed
Error message
Response already committed
What it means
VertxHttpResponse.reset() implements the servlet-style reset contract: once the response is committed (headers/status already sent to the wire), it cannot be reset. It throws IllegalStateException("Response already committed") to prevent mutating headers of a response the client has already started receiving.
Source
Thrown at extensions/resteasy-classic/resteasy/runtime/src/main/java/io/quarkus/resteasy/runtime/standalone/VertxHttpResponse.java:115
}
response.setStatusCode(status);
if (message != null) {
response.end(message);
} else {
response.end();
}
committed = true;
}
@Override
public boolean isCommitted() {
return committed;
}
@Override
public void reset() {
if (committed) {
throw new IllegalStateException("Response already committed");
}
outputHeaders.clear();
}
private void transformHeaders() {
getOutputHeaders().forEach(this::transformHeadersList);
}
private void transformHeadersList(final String key, final List<Object> valueList) {
final MultiMap headers = response.headers();
for (Object value : valueList) {
if (value == null) {
headers.add(key, "");
} else {
RuntimeDelegate.HeaderDelegate delegate = providerFactory.getHeaderDelegate(value.getClass());
if (delegate != null) {
headers.add(key, delegate.toString(value));
} else {View on GitHub (pinned to e1c734241f)
Solutions
- Only reset before writing any entity/status — restructure error handling so failures are detected before the first write/flush.
- Instead of reset after commit, log the issue and close the stream; the client already received the committed response.
- Use flush() deliberately and late: avoid premature flushing in mappers/interceptors so reset remains possible for error paths.
Example fix
// before
try {
out.write(data);
} catch (Exception e) {
response.reset(); // IllegalStateException: already committed
response.setStatusCode(500);
}
// after
boolean ok = renderData(out); // validate/build first, write last
if (!ok) {
response.setStatusCode(500); // nothing written yet, safe
} Defensive patterns
Strategy: validation
Validate before calling
if (response.isCommitted()) {
throw new IllegalStateException("Cannot reset: response already committed");
}
response.reset(); Type guard
boolean safeToReset(io.quarkus.resteasy.runtime.standalone.VertxHttpResponse resp) {
return !resp.isCommitted();
} Try / catch
try {
response.reset();
} catch (IllegalStateException e) {
LOG.warn("Response already committed; cannot reset — client received partial response");
} Prevention
- Validate inputs and resolve errors before writing any entity or headers.
- Avoid flushing early in interceptors/mappers so the response stays resettable.
- Never call reset() from finally blocks.
- Use exception mappers that run before output starts (handle exceptions before first write).
When it happens
Trigger: Calling response.reset() (directly or via getOutputStream side effects / container machinery) after the response was flushed or its headers written; e.g. an exception handler trying to reset the response to send a different status after partial output was committed.
Common situations: Custom error handling that attempts to change the status code after output started; exception mappers firing after the entity stream was flushed; frameworks that reset responses defensively in finally blocks.
Related errors
- Proxy type HTTP is required
- Failed to write
- Dev services for ${request.getName()} requires a startable s
- Can only be called at runtime
- Build time property cannot be changed at runtime: ${mismatch
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/f76103cb5688e69e.
Report an issue: GitHub.