quarkusio/quarkus · error · IllegalStateException
Cannot write more than one piece of async data at a time
Error message
Cannot write more than one piece of async data at a time
What it means
ServletRequestContext (the servlet bridge for RESTEasy Reactive) only supports one outstanding asynchronous write on the servlet output stream at a time. write() throws this IllegalStateException, inside a synchronized block, if another async write (asyncWriteData) is still pending. It protects against interleaving blocking and async response writes.
Source
Thrown at extensions/resteasy-reactive/rest-servlet/runtime/src/main/java/io/quarkus/resteasy/reactive/server/servlet/runtime/ServletRequestContext.java:516
return this;
}
@Override
public ServerHttpResponse write(byte[] data, Consumer<Throwable> asyncResultHandler) {
if (asyncWriteData != null) {
asyncResultHandler.accept(new IllegalStateException("Cannot write before data has all been written"));
}
if (asyncContext == null) {
try {
response.getOutputStream().write(data);
asyncResultHandler.accept(null);
} catch (IOException e) {
asyncResultHandler.accept(e);
}
} else {
synchronized (this) {
if (asyncWriteData != null) {
throw new IllegalStateException("Cannot write more than one piece of async data at a time");
}
asyncWriteData = data;
asyncWriteHandler = asyncResultHandler;
if (writeListener == null) {
try {
ServletOutputStream outputStream = response.getOutputStream();
outputStream.setWriteListener(writeListener = new ServletWriteListener(outputStream));
} catch (IOException e) {
asyncResultHandler.accept(e);
}
} else {
writeListener.onWritePossible();
}
}
}
return this;
}
View on GitHub (pinned to e1c734241f)
Solutions
- Wait for the asyncResultHandler callback (success or failure) before issuing the next write
- Serialize writes through a single thread or an orderly queue so only one write is in flight
- On callback completion, clear asyncWriteData state (the implementation does this) before continuing
- If streaming large payloads, use a blocking-safe write loop on a worker thread instead of stacked async writes
Example fix
// before ctx.write(chunk1, handler); ctx.write(chunk2, handler); // throws // after ctx.write(chunk1, handler); handler.thenRun(() -> ctx.write(chunk2, handler));
Defensive patterns
Strategy: try-catch
Validate before calling
synchronized (ctx) {
boolean safe = (pendingWrites.get(ctx) == 0); // track in-flight writes externally
}
// only issue next write when previous asyncResultHandler completed Type guard
boolean canWrite(ServletRequestContext ctx) {
return !ctxHasPendingAsyncWrite(ctx); // maintain your own in-flight flag
} Try / catch
try {
ctx.write(data, handler);
} catch (IllegalStateException e) {
queue.offer(data); // retry after current write completes
} Prevention
- Write the next chunk only inside the async result handler callback
- Never call write concurrently from multiple threads on the same response
- Serialize streaming through a single writer/queue
- Track outstanding async writes with a counter
When it happens
Trigger: Calling write(byte[], io.quarkus.vertx.core.runtime.context.SafeWritableOutputStream-like handler) while a previous async write has not completed; calling write twice before the write listener reports completion; concurrent writes from multiple threads on the same response context.
Common situations: Custom response streaming code writing chunks without awaiting the async result handler; servlet async write listener not invoked (client slow), so the next write hits the pending slot; mixing blocking and async output APIs on the same request.
Related errors
- Async can only be started once
- No producers for required item %s, step builder used: %s
- cycle detection failure report (dynamic CycleBuildException
- Build step '%s' does not produce any build item and thus wil
- Cannot consume/produce interface or abstract class build ite
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/20148098c31d4444.
Report an issue: GitHub.