quarkusio/quarkus · error · IllegalArgumentException
Wrong Vert.x context used for multipart upload. Expected: "
Error message
Wrong Vert.x context used for multipart upload. Expected: " + context + ", actual: " + Vertx.currentContext()
What it means
QuarkusMultipartFormUpload.run() asserts that the encoding loop executes on the Vert.x context captured at construction time. If Vertx.currentContext() differs from the expected context it throws this IllegalArgumentException, because multipart encoding mutates shared Netty state that is not safe across contexts. This guards against the upload being driven from the wrong thread/context.
Source
Thrown at independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/QuarkusMultipartFormUpload.java:164
} else {
return;
}
}
handler.handle(item);
}
private void clearEncoder() {
if (encoder == null) {
return;
}
encoder.cleanFiles();
encoder = null;
}
@Override
public void run() {
if (Vertx.currentContext() != context) {
throw new IllegalArgumentException("Wrong Vert.x context used for multipart upload. Expected: " + context +
", actual: " + Vertx.currentContext());
}
while (!ended) {
if (encoder.isChunked()) {
try {
HttpContent chunk = encoder.readChunk(ALLOC);
if (chunk == PausableHttpPostRequestEncoder.WAIT_MARKER) {
return; // resumption will be scheduled by encoder
} else if (chunk == LastHttpContent.EMPTY_LAST_CONTENT || encoder.isEndOfInput()) {
ended = true;
request = null;
clearEncoder();
pending.write(InboundBuffer.END_SENTINEL);
} else {
ByteBuf content = chunk.content();
Buffer buff = BufferInternal.buffer(content);
boolean writable = pending.write(buff);
if (!writable) {View on GitHub (pinned to e1c734241f)
Solutions
- Ensure the multipart upload is driven on the original Vert.x context; do not wrap run() in executeBlocking or move it to another executor
- If work must happen elsewhere, hop back with context.runOnContext(v -> upload.run()) before encoding
- Let the REST client and Vert.x WebClient drive the request themselves instead of manually invoking the upload loop
Example fix
// before
workerExecutor.executeBlocking(promise -> {
upload.run();
promise.complete();
});
// after
context.runOnContext(v -> upload.run()); Defensive patterns
Strategy: try-catch
Validate before calling
if (Vertx.currentContext() != expectedContext) {
expectedContext.runOnContext(v -> upload.run());
} else {
upload.run();
} Try / catch
try {
upload.run();
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Wrong Vert.x context")) {
expectedContext.runOnContext(v -> upload.run());
} else {
throw e;
}
} Prevention
- Never wrap multipart upload loops in executeBlocking or custom executors
- Capture the Context at creation time and always use runOnContext to return to it
- Avoid manually driving the upload; let the REST client pipeline own it
When it happens
Trigger: Calling the upload's run()/drain logic from a different Vert.x context than the one that created the QuarkusMultipartFormUpload, e.g. scheduling the write loop on a worker thread or a different context via executeBlocking, custom thread pools, or resuming the request from another context.
Common situations: Offloading multipart encoding to a worker thread with executeBlocking; integrating the client with third-party reactive libraries that shift contexts; custom interceptors/filters that resume the HTTP request on the wrong context; version upgrades that changed which context the client runs on.
Related errors
- MultiByteHttpData invoked on an invalid context :
- Multipart field name filename cannot be null when sending fi
- Multipart field name pathname cannot be null when sending fi
- The Vert.x Context to attach the OpenTelemetry Context must
- The Vert.x Context is not set
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/b3bee82b07ac961a.
Report an issue: GitHub.