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

  1. Track ended state in your code and guard: if (!ended) parser.end()
  2. Use end() in exactly one place — prefer the stream endHandler
  3. 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

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


AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06). Data as JSON: /api/errors/98f353681f577701. Report an issue: GitHub.