{"id":"1b059d4232aeda78","repo":"google/gson","slug":"json-document-was-not-fully-consumed","errorCode":null,"errorMessage":"JSON document was not fully consumed.","messagePattern":"JSON document was not fully consumed\\.","errorType":"exception","errorClass":"JsonSyntaxException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/Gson.java","lineNumber":1222,"sourceCode":"   *\n   * @return an object of type T from the JSON. Returns {@code null} if {@code json} is {@code null}\n   *     or if {@code json} is empty.\n   * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT\n   * @see #fromJson(Reader, TypeToken)\n   * @see #fromJson(JsonElement, Class)\n   * @since 2.10\n   */\n  public <T> T fromJson(JsonElement json, TypeToken<T> typeOfT) throws JsonSyntaxException {\n    if (json == null) {\n      return null;\n    }\n    return fromJson(new JsonTreeReader(json), typeOfT);\n  }\n\n  private static void assertFullConsumption(Object obj, JsonReader reader) {\n    try {\n      if (obj != null && reader.peek() != JsonToken.END_DOCUMENT) {\n        throw new JsonSyntaxException(\"JSON document was not fully consumed.\");\n      }\n    } catch (MalformedJsonException e) {\n      throw new JsonSyntaxException(e);\n    } catch (IOException e) {\n      throw new JsonIOException(e);\n    }\n  }\n\n  /**\n   * Proxy type adapter for cyclic type graphs.\n   *\n   * <p><b>Important:</b> Setting the delegate adapter is not thread-safe; instances of {@code\n   * FutureTypeAdapter} must only be published to other threads after the delegate has been set.\n   *\n   * @see Gson#threadLocalAdapterResults\n   */\n  static class FutureTypeAdapter<T> extends SerializationDelegatingTypeAdapter<T> {\n    private TypeAdapter<T> delegate = null;","sourceCodeStart":1204,"sourceCodeEnd":1240,"githubUrl":"https://github.com/google/gson/blob/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/Gson.java#L1204-L1240","documentation":"Thrown by assertFullConsumption (called from Gson.fromJson(Reader, TypeToken)) when, after successfully reading one JSON value, the reader still has more tokens (peek() != END_DOCUMENT). The Reader/TypeToken overload enforces single-value documents to catch trailing garbage; multiple top-level values or trailing whitespace-with-data are rejected. It is a JsonSyntaxException (a RuntimeException).","triggerScenarios":"Feeding gson.fromJson(reader, TypeToken.get(Foo.class)) a stream containing two concatenated JSON objects {\"a\":1}{\"b\":2}; a value followed by trailing non-whitespace; an array where a single object was expected, or vice versa, leaving remainder; NDJSON/JSON Lines fed to a single-value parser.","commonSituations":"Concatenated responses from a server; NDJSON log files; buffered streams that include the next message; copy-paste of multiple JSON snippets into one input; incorrect framing of a network protocol.","solutions":["Use the JsonReader-based overload gson.fromJson(JsonReader, TypeToken) which does NOT enforce full consumption and lets you loop over multiple top-level values.","Strip trailing data or split the input into single JSON values before parsing.","For NDJSON, read line-by-line and parse each line separately.","Validate that the input contains exactly one top-level JSON value before calling the Reader overload."],"exampleFix":"// before: two values in one Reader\nString two = \"{\\\"a\\\":1}{\\\"b\\\":2}\";\nFoo f = gson.fromJson(new StringReader(two), TypeToken.get(Foo.class)); // throws\n\n// after: use JsonReader to consume multiple values\ntry (JsonReader r = new JsonReader(new StringReader(two))) {\n  while (r.peek() != JsonToken.END_DOCUMENT) {\n    Foo f = gson.fromJson(r, TypeToken.get(Foo.class));\n  }\n}","handlingStrategy":"validation","validationCode":"// Validate single top-level value before the Reader overload\nstatic boolean hasSingleTopLevel(String json) {\n  JsonReader r = new JsonReader(new StringReader(json));\n  try {\n    r.skipValue();\n    return r.peek() == JsonToken.END_DOCUMENT;\n  } catch (IOException e) { return false; }\n}","typeGuard":"static boolean isSingleValueDocument(Reader reader) {\n  JsonReader r = new JsonReader(reader);\n  try { r.skipValue(); return r.peek() == JsonToken.END_DOCUMENT; }\n  catch (IOException e) { return false; }\n}","tryCatchPattern":"try {\n  Foo f = gson.fromJson(reader, TypeToken.get(Foo.class));\n} catch (JsonSyntaxException e) {\n  if (e.getMessage().contains(\"not fully consumed\")) {\n    // switch to JsonReader-based loop for multi-value streams\n  } else throw e;\n}","preventionTips":["Use the JsonReader overload (fromJson(JsonReader, TypeToken)) for streams with multiple values; it does not enforce full consumption.","Split NDJSON into lines and parse each line separately.","Validate single top-level value before using the Reader overload.","Frame network/streamed JSON correctly so only one message reaches each parse call."],"tags":["gson-core","deserialization","trailing-data","json-reader","ndjson"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}