eclipse-vertx/vert.x · error · DecodeException
Unexpected trailing token
Error message
Unexpected trailing token
What it means
After parsing the requested JSON value, JacksonCodec checks that the parser has been fully consumed (no remaining token). If extra content follows the first complete JSON value, it throws DecodeException("Unexpected trailing token"). This enforces that the input is exactly one JSON document.
Source
Thrown at vertx-core/src/main/java/io/vertx/core/json/jackson/JacksonCodec.java:280
public Object fromBuffer(Buffer buf) throws DecodeException {
return fromParser(createParser(buf), Object.class);
}
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 (IOException e) {
throw new DecodeException(e.getMessage(), e);
} finally {
close(parser);
}
if (remaining != null) {
throw new DecodeException("Unexpected trailing token");
}
return cast(res, type);
}
/**
* Parse a JSON value given the {@code parser}, consuming the current parser token and possibly more
* when parsing an object or an array.
*
* @param parser the parser
* @return the parsed value as an object
*/
public static Object parseValue(JsonParser parser) throws IOException, DecodeException {
switch (parser.currentTokenId()) {
case JsonTokenId.ID_START_OBJECT:
return internalParseObject(parser);
case JsonTokenId.ID_START_ARRAY:
return internalParseArray(parser);
case JsonTokenId.ID_STRING:View on GitHub (pinned to fb308bd8c3)
Solutions
- Remove or split the trailing data — parse each JSON document separately (split on newline for NDJSON)
- Validate the payload contains exactly one JSON document before decoding
- If multiple documents are expected, parse them individually in a loop with a streaming parser
- Trim whitespace/BOM; if the extra token is unexpected, log the raw tail and fix the producer
Example fix
// before
Object o = Json.decodeValue(ndjsonBuffer); // '{...}\n{...}' throws
// after
for (String line : ndjsonBuffer.toString().split("\n")) {
if (line.isBlank()) continue;
Object o = Json.decodeValue(line);
handle(o);
} Defensive patterns
Strategy: validation
Validate before calling
// Java
// Ensure exactly one JSON document per decode unit
public static List<String> splitJsonDocuments(String payload) {
return java.util.Arrays.stream(payload.split("\n"))
.map(String::strip)
.filter(s -> !s.isEmpty())
.toList();
} Type guard
public static boolean isSingleJsonDocument(String s) {
if (s == null) return false;
String t = s.strip();
if (t.isEmpty()) return false;
try (com.fasterxml.jackson.core.JsonParser p = JacksonCodec.createParser(t)) {
while (p.nextToken() != null) { /* consume */ }
return true;
} catch (Exception e) { return false; }
} Try / catch
try {
return Json.decodeValue(buffer);
} catch (DecodeException e) {
if (e.getMessage().contains("Unexpected trailing token")) {
// input has multiple documents: split and decode each
return splitJsonDocuments(buffer.toString()).stream()
.map(Json::decodeValue).toList();
}
throw e;
} Prevention
- Never concatenate JSON documents; wrap multiple values in an array
- Handle NDJSON by splitting on newlines and decoding per line
- Trim BOM and trailing whitespace before decoding
- Agree on single-document payloads with upstream producers
When it happens
Trigger: Calling fromString/fromBuffer/fromStream/fromReader with input that contains a valid JSON value followed by extra data — e.g. 'null null', '{...} garbage', NDJSON/multiple concatenated JSON documents, or an HTTP body with appended bytes.
Common situations: Decoding newline-delimited JSON (NDJSON) streams a document at a time but passing the whole payload; concatenating JSON responses without an array wrapper; binary padding or a stray BOM/whitespace artifact after the JSON; proxy pipelines that append data.
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
- Unexpected trailing token
- Unexpected trailing token
- Failed to decode:${e.getMessage()}
- Mapping ${toValueType.getName()} is not available without J
- Failed to decode:
AI-assisted analysis of eclipse-vertx/vert.x@fb308bd8c3 (2026-09-06).
Data as JSON: /api/errors/35024eaf23b8e0d7.
Report an issue: GitHub.