eclipse-vertx/vert.x · error · DecodeException

Unexpected trailing token

Error message

Unexpected trailing token

What it means

After Jackson reads the requested value, fromParser checks for another token; if the input contains extra non-whitespace content after the first value it throws DecodeException 'Unexpected trailing token'. Vert.x decodes exactly one JSON value per call.

Source

Thrown at vertx-core/src/main/java/io/vertx/core/json/jackson/DatabindCodec.java:135

      return DatabindCodec.mapper.getFactory().createParser(str);
    } catch (IOException e) {
      throw new DecodeException("Failed to decode:" + e.getMessage(), e);
    }
  }

  public static <T> T fromParser(JsonParser parser, Class<T> type) throws DecodeException {
    T value;
    JsonToken remaining;
    try {
      value = DatabindCodec.mapper.readValue(parser, type);
      remaining = parser.nextToken();
    } catch (Exception e) {
      throw new DecodeException("Failed to decode:" + e.getMessage(), e);
    } finally {
      close(parser);
    }
    if (remaining != null) {
      throw new DecodeException("Unexpected trailing token");
    }
    if (type == Object.class) {
      value = (T) adapt(value);
    }
    return value;
  }

  private static <T> T fromParser(JsonParser parser, TypeReference<T> type) throws DecodeException {
    T value;
    try {
      value = DatabindCodec.mapper.readValue(parser, type);
    } catch (Exception e) {
      throw new DecodeException("Failed to decode:" + e.getMessage(), e);
    } finally {
      close(parser);
    }
    if (type.getType() == Object.class) {
      value = (T) adapt(value);

View on GitHub (pinned to fb308bd8c3)

Solutions

  1. Decode one value at a time; split NDJSON by '\n' and decode each line.
  2. Trim the payload and inspect the tail for extra objects/values.
  3. If multiple values are expected, use JacksonParser streaming manually or a JSON-lines parser.
  4. Fix the producer to send exactly one JSON document per message.

Example fix

// before
Json.decodeValue(line1 + line2, Config.class); // trailing token
// after
for (String line : payload.split("\n")) {
  Config c = Json.decodeValue(line, Config.class);
}
Defensive patterns

Strategy: validation

Validate before calling

String t = raw.trim();
int end = indexOfMatchingValue(t); // or simply: assert exactly one top-level value
if (countTopLevelValues(t) > 1) throw new IllegalStateException("payload contains multiple JSON values");

Type guard

static boolean isSingleJsonValue(String s) {
  try {
    JsonParser p = new ObjectMapper().getFactory().createParser(s);
    p.nextToken();
    boolean single = p.nextToken() == null;
    p.close();
    return single;
  } catch (Exception e) { return false; }
}

Try / catch

try {
  Config c = Json.decodeValue(raw, Config.class);
} catch (DecodeException e) {
  if ("Unexpected trailing token".equals(e.getMessage())) {
    // split NDJSON or fix producer framing
  }
}

Prevention

When it happens

Trigger: Json.decodeValue('{"a":1} {"b":2}') — two JSON objects concatenated; newline-delimited JSON fed as a whole; logs/concatenated payloads with a stray second value; invisible trailing characters that Jackson still tokenizes.

Common situations: NDJSON streams consumed without splitting on newlines; accumulating multiple frames into one buffer before decoding; copy-paste of several JSON documents into one config file.

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/c6b906506038e9e3. Report an issue: GitHub.