quarkusio/quarkus · error · IllegalStateException
MultiByteHttpData invoked on an invalid context :
Error message
MultiByteHttpData invoked on an invalid context :
What it means
MultiByteHttpData mutates a non-thread-safe ByteBuf and drives a Vert.x-context-bound subscription, so getChunk(int) may only be called on the exact Vert.x Context captured at construction. getChunk verifies Vertx.currentContext() == context and throws IllegalStateException when invoked from a different context or thread (the message prints the offending context and thread).
Source
Thrown at independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/MultiByteHttpData.java:197
* @return true if the requested amount of bytes is ready to be read or the Multi is completed, i.e. there will be
* no more bytes to read
*/
public boolean isReady(int chunkSize) {
return done || buffer.readableBytes() >= chunkSize;
}
/**
* {@inheritDoc}
* <br/>
* NOTE: should only be invoked when {@link #isReady(int)} returns true
*
* @param toRead amount of bytes to read
* @return ByteBuf with the requested bytes
*/
@Override
public ByteBuf getChunk(int toRead) {
if (Vertx.currentContext() != context) {
throw new IllegalStateException("MultiByteHttpData invoked on an invalid context : " + Vertx.currentContext()
+ ", thread: " + Thread.currentThread());
}
if (buffer.readableBytes() == 0 && done) {
return Unpooled.EMPTY_BUFFER;
}
ByteBuf result = VertxByteBufAllocator.DEFAULT.heapBuffer(toRead, toRead);
// finish if the whole buffer is filled
// or we hit the end, `done` && buffer.readableBytes == 0
while (toRead > 0 && !(buffer.readableBytes() == 0 && done)) {
int readBytes = Math.min(buffer.readableBytes(), toRead);
result.writeBytes(buffer.readBytes(readBytes));
buffer.discardReadBytes();
subscription.request(readBytes);
toRead -= readBytes;
}View on GitHub (pinned to e1c734241f)
Solutions
- Ensure encoding/read of chunks happens on the same Vert.x context that created the part - submit work via context.runOnContext(...) or the client's ExecutorWithContext.
- Do not call getChunk from arbitrary threads; route through PausableHttpPostRequestEncoder, which preserves the context.
- In tests, run getChunk inside Vertx.testContext().runOnContext(...) or capture the exact context used by the client.
- If you implemented custom resumption logic, make sure resumption.run() executes on the captured context (it is invoked from the Multi emissions, which are context-bound via ExecutorWithContext).
Example fix
// before
byte[] data = readChunkFromWorkerThread(httpData); // calls getChunk off-context
// after
context.runOnContext(v -> {
if (httpData.isReady(chunkSize)) {
ByteBuf chunk = httpData.getChunk(chunkSize);
// ... use chunk here
}
}); Defensive patterns
Strategy: validation
Validate before calling
if (Vertx.currentContext() != partContext) {
throw new IllegalStateException("getChunk must run on the Vert.x context that created the part");
}
httpData.getChunk(toRead); Type guard
boolean onValidContext(MultiByteHttpData data) {
return Vertx.currentContext() == data.getCurrentContextOrNull(); // only if exposed; otherwise capture the context at part creation
} Try / catch
try {
httpData.getChunk(toRead);
} catch (IllegalStateException e) {
if (e.getMessage() != null && e.getMessage().startsWith("MultiByteHttpData invoked on an invalid context")) {
// resubmit the read on the captured part context via context.runOnContext(...)
} else {
throw e;
}
} Prevention
- Keep multipart encoding on the Vert.x context that created the part.
- Never call getChunk from worker threads or custom executors.
- Route chunk reads through PausableHttpPostRequestEncoder.
- In tests, wrap getChunk calls in context.runOnContext(...).
When it happens
Trigger: Calling getChunk(int) from a thread whose Vert.x currentContext() differs from the context passed to the MultiByteHttpData constructor - e.g. from a plain worker thread, a Mutiny infrastructure thread, or a different Vert.x context than the one running the client request.
Common situations: Custom or wrapped post encoders that encode the multipart body on their own executor; moving encoding work off the IO thread; unit tests invoking getChunk directly from the test thread; callbacks that hop contexts before draining part data.
Related errors
- Wrong Vert.x context used for multipart upload. Expected: "
- No Vertx context found
- No Vertx context found
- No Vertx context found
- The Vert.x Context to attach the OpenTelemetry Context must
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/fb45b8ad0d5934b3.
Report an issue: GitHub.