eclipse-vertx/vert.x · error · IllegalStateException
Parsing already done
Error message
Parsing already done
What it means
JsonParser follows a stream lifecycle: once end() has been called the parse is complete and the instance cannot accept more input. Calling end() a second time throws IllegalStateException('Parsing already done'). The 'ended' flag is checked before signaling end-of-input to the underlying Jackson parser.
Source
Thrown at vertx-core/src/main/java/io/vertx/core/parsetools/impl/JsonParserImpl.java:168
}
@Override
public void handle(Buffer data) {
byte[] bytes = data.getBytes();
try {
parser.feedInput(bytes, 0, bytes.length);
} catch (IOException e) {
handle(e);
}
checkTokens();
checkPending();
checkExceptions();
}
@Override
public void end() {
if (ended) {
throw new IllegalStateException("Parsing already done");
}
ended = true;
parser.endOfInput();
checkTokens();
checkPending();
checkExceptions();
}
private void checkTokens() {
JsonLocation prevLocation = null;
while (true) {
JsonToken token;
try {
token = parser.nextToken();
} catch (IOException e) {
JsonLocation location = parser.currentLocation();
if (prevLocation != null) {
if (location.equals(prevLocation)) {View on GitHub (pinned to fb308bd8c3)
Solutions
- Track ended state in your code and guard: if (!ended) parser.end()
- Use end() in exactly one place — prefer the stream endHandler
- Create a fresh JsonParser if a new document/stream must be parsed
Example fix
// before
stream.endHandler(v -> parser.end());
// later
parser.end(); // IllegalStateException
// after
AtomicBoolean ended = new AtomicBoolean();
stream.endHandler(v -> { if (ended.compareAndSet(false, true)) parser.end(); }); Defensive patterns
Strategy: validation
Validate before calling
if (!ended.get()) {
parser.end();
} Try / catch
try {
parser.end();
} catch (IllegalStateException e) {
// already ended: safe to ignore
} Prevention
- Call end() from exactly one code path (usually the stream endHandler)
- Track ended state with an AtomicBoolean
- Never reuse a JsonParser across streams — create a new one per document
When it happens
Trigger: Calling parser.end() twice, e.g. from both the stream endHandler and an explicit completion path; resuming a parser after completion to feed more buffers.
Common situations: Wiring the same parser to stream end and writeEnd(); retry logic that re-finishes a parser; framework adapters that may invoke end more than once on empty streams.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot set connectHandler when server is listening
- Cannot set exceptionHandler when server is listening
- Already started
- Event Bus is not started
- Server already bound
AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06).
Data as JSON: /api/errors/98f353681f577701.
Report an issue: GitHub.