eclipse-vertx/vert.x · error · IllegalStateException
Only the context thread can write a message
Error message
Only the context thread can write a message
What it means
Thrown by Http1ServerResponse.checkThread() when conn.strictThreadMode is enabled and a write/end call is made from a thread other than the request's context (event-loop) thread. Vert.x strict thread mode enforces that all response writes happen on the owning context to keep single-threaded guarantees.
Source
Thrown at vertx-core/src/main/java/io/vertx/core/http/impl/http1/Http1ServerResponse.java:107
Http1ServerConnection conn,
HttpRequest request,
Object requestMetric,
boolean keepAlive) {
this.vertx = vertx;
this.conn = conn;
this.context = context;
this.version = request.protocolVersion();
this.headers = Http1xHeaders.httpHeaders();
this.request = request;
this.status = HttpResponseStatus.OK;
this.requestMetric = requestMetric;
this.keepAlive = keepAlive;
this.head = request.method() == io.netty.handler.codec.http.HttpMethod.HEAD;
}
private void checkThread() {
if (conn.strictThreadMode && !context.executor().inThread()) {
throw new IllegalStateException("Only the context thread can write a message");
}
}
@Override
public MultiMap headers() {
return headers;
}
@Override
public MultiMap trailers() {
if (trailers == null) {
Http1xHeaders v = Http1xHeaders.httpHeaders();
trailers = v;
trailingHeaders = v;
}
return trailers;
}
View on GitHub (pinned to fb308bd8c3)
Solutions
- Dispatch the write onto the request's context with context.runOnContext(v -> response.end()) or vertx.runOnContext
- Perform writes only inside Vert.x handlers (event loop), keep other threads for computation only
- Disable strictThreadMode if cross-thread writes are intentional (not recommended)
Example fix
// before
executor.submit(() -> response.end("done"));
// after
executor.submit(() -> context.runOnContext(v -> response.end("done"))); Defensive patterns
Strategy: try-catch
Validate before calling
// ensure writes run on the owning context Context ctx = vertx.getOrCreateContext(); if (!ctx.equals(response.vertx().getOrCreateContext())) ctx.runOnContext(v -> response.end());
Try / catch
try { response.end(buf); } catch (IllegalStateException e) { context.runOnContext(v -> response.end(buf)); } Prevention
- Only write responses from Vert.x handler threads
- Use context.runOnContext when jumping threads
- Avoid ending responses from custom executor pools
- Keep strictThreadMode in mind when designing worker usage
When it happens
Trigger: Calling response.write(), response.end(), writeHead(), writeContinue(), writeEarlyHints() or netSocket() from a worker thread, a custom executor, or a user thread while the connection was created with strictThreadMode=true.
Common situations: Writing the response from a CompletableFuture callback or application thread pool; blocking worker doing the response; tests running code on the main thread.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Cannot write an HTTP/2 frame over an HTTP/1.x connection
- HTTP/1.x connections don't support SETTINGS
- HTTP/1.x connections don't support PING
- Request must have a content-type header to decode a multipar
- Request must have a valid content-type header to decode a mu
AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06).
Data as JSON: /api/errors/ed8f5c947a23307d.
Report an issue: GitHub.