{"record":{"id":"3d9d77145cfe40e2","repo":"eclipse-vertx/vert.x","slug":"unexpected-trailing-token-3d9d77","errorCode":null,"errorMessage":"Unexpected trailing token","messagePattern":"Unexpected trailing token","errorType":"exception","errorClass":"DecodeException","httpStatus":null,"severity":"error","filePath":"vertx-core/src/main/java21/io/vertx/core/json/jackson/v3/DatabindCodec.java","lineNumber":114,"sourceCode":"  }\n\n  public static JsonParser createParser(String str) {\n    return DatabindCodec.mapper.createParser(str);\n  }\n\n  public static <T> T fromParser(JsonParser parser, Class<T> type) throws DecodeException {\n    T value;\n    JsonToken remaining;\n    try {\n      value = DatabindCodec.mapper.readValue(parser, type);\n      remaining = parser.nextToken();\n    } catch (Exception e) {\n      throw new DecodeException(\"Failed to decode:\" + e.getMessage(), e);\n    } finally {\n      close(parser);\n    }\n    if (remaining != null) {\n      throw new DecodeException(\"Unexpected trailing token\");\n    }\n    if (type == Object.class) {\n      value = (T) adapt(value);\n    }\n    return value;\n  }\n\n  private static <T> T fromParser(JsonParser parser, TypeReference<T> type) throws DecodeException {\n    T value;\n    try {\n      value = DatabindCodec.mapper.readValue(parser, type);\n    } catch (Exception e) {\n      throw new DecodeException(\"Failed to decode:\" + e.getMessage(), e);\n    } finally {\n      close(parser);\n    }\n    if (type.getType() == Object.class) {\n      value = (T) adapt(value);","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java21/io/vertx/core/json/jackson/v3/DatabindCodec.java#L96-L132","documentation":"After Jackson successfully binds a value in DatabindCodec.fromParser, the codec calls parser.nextToken() to confirm the stream ends. If another token remains (extra JSON content after the first value), it throws DecodeException('Unexpected trailing token'). This enforces that input contains exactly one JSON value with nothing after it.","triggerScenarios":"Json.decodeValue on input containing concatenated values like '{}{}' or '[1,2] extra', or newline-delimited JSON (NDJSON) fed to a single-value decoder; whitespace is fine, extra tokens are not.","commonSituations":"NDJSON logs streamed into Json.decodeValue instead of a line-by-line parser; a producer accidentally emitting the same object twice; concatenating buffered HTTP chunks that each hold a JSON document.","solutions":["Split the input and decode one JSON document at a time (e.g. split on lines for NDJSON and call decodeValue per line).","Trim/sanitize the payload so only one JSON value remains.","Fix the producer that is concatenating JSON documents.","If multi-document input is expected, use Jackson's MappingIterator via mapper.readValues(parser, type) instead of single-value decode."],"exampleFix":"// before\nJsonObject o = Json.decodeValue(ndjsonBuffer, JsonObject.class); // two lines -> fails\n// after\nJsonObject o = Json.decodeValue(ndjsonBuffer.toString().split(\"\\n\")[0], JsonObject.class);","handlingStrategy":"validation","validationCode":"boolean singleJsonDocument(String s) {\n  String t = s.trim();\n  // quick sanity: first non-space char opens, last closes, and lengths plausibly match one doc\n  return t.startsWith(\"{\") || t.startsWith(\"[\") || t.startsWith(\"\\\"\") || t.matches(\"^-?\\\\d.*\") || t.equals(\"true\") || t.equals(\"false\") || t.equals(\"null\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  JsonObject o = Json.decodeValue(buf, JsonObject.class);\n} catch (DecodeException e) {\n  if (e.getMessage().contains(\"trailing token\")) {\n    // split and decode each document separately\n  }\n}","preventionTips":["Never feed NDJSON/multi-document streams to a single-value decoder; split first.","Ensure producers emit exactly one JSON document per message.","Concatenate buffers only after confirming they form a single document."],"tags":["json","decoding","codec","trailing-data"],"backgroundTag":"json-decode-failed","analyzedSha":"fb308bd8c3f12c79f4ae89bef67fadf6c80d036e","analyzedAt":"2026-09-06T11:37:12.241Z","contentChangedAt":"2026-09-06T11:37:12.241Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}