eclipse-vertx/vert.x · error · DecodeException

Unexpected trailing token

Error message

Unexpected trailing token

What it means

JacksonCodec.fromParser consumes a JsonParser expecting exactly one JSON value; after decoding, any leftover tokens (unless a deferred 'remaining' state was intentionally kept) mean the input contains more content than a single value. The codec throws DecodeException("Unexpected trailing token") in that case. This guards against inputs like '{...} {...}' or a value followed by garbage.

Source

Thrown at vertx-core/src/main/java21/io/vertx/core/json/jackson/v3/JacksonCodec.java:240

  private static JsonGenerator createGenerator(OutputStream out, boolean pretty) {
    return factory.createGenerator(owc(pretty), out);
  }

  public static <T> T fromParser(JsonParser parser, Class<T> type) throws DecodeException {
    Object res;
    JsonToken remaining;
    try {
      parser.nextToken();
      res = parseValue(parser);
      remaining = parser.nextToken();
    } catch (JacksonException | IOException e) {
      throw new DecodeException(e.getMessage(), e);
    } finally {
      close(parser);
    }
    if (remaining != null) {
      throw new DecodeException("Unexpected trailing token");
    }
    return cast(res, type);
  }

  private static Object parseValue(JsonParser parser) throws IOException, DecodeException {
    switch (parser.currentTokenId()) {
      case JsonTokenId.ID_START_OBJECT:
        return parseObject(parser);
      case JsonTokenId.ID_START_ARRAY:
        return parseArray(parser);
      case JsonTokenId.ID_STRING:
        return parser.getString();
      case JsonTokenId.ID_NUMBER_FLOAT:
      case JsonTokenId.ID_NUMBER_INT:
        return parser.getNumberValue();
      case JsonTokenId.ID_TRUE:
        return Boolean.TRUE;
      case JsonTokenId.ID_FALSE:

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Ensure the input contains exactly one JSON value; split NDJSON input into lines and decode each line separately
  2. Strip or trim extraneous characters from the payload before decoding
  3. If multiple concatenated values are intentional, use a streaming/token-by-token parse loop instead of fromParser

Example fix

// before
String ndjson = "{\"a\":1}\n{\"a\":2}";
Object o = Json.decodeValue(ndjson); // DecodeException: Unexpected trailing token
// after
List<Object> all = new ArrayList<>();
for (String line : ndjson.split("\n")) all.add(Json.decodeValue(line));
Defensive patterns

Strategy: try-catch

Validate before calling

// single-value check before decode
String t = input.trim();
if (!(t.startsWith("{") || t.startsWith("["))) throw new IllegalArgumentException("not JSON");
// for suspected NDJSON, ensure exactly one line: input.indexOf('\n') == -1

Try / catch

try {
  Object o = Json.decodeValue(buffer);
} catch (DecodeException e) {
  if (e.getMessage().contains("Unexpected trailing token")) {
    // split input into multiple documents and decode each
  }
}

Prevention

When it happens

Trigger: Calling JacksonCodec.fromParser (directly or via Json.decodeValue with an ObjectMapper readTree-style flow) on input containing more than one top-level JSON value, e.g. JSON Lines fed to a single-value decoder, concatenated JSON objects, or a JSON value followed by extra characters.

Common situations: NDJSON/log-line files parsed as one JSON document; two JSON payloads accidentally concatenated by a producer; trailing whitespace is fine but an accidental second token (comma-separated records) triggers this.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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