{"record":{"id":"579fd59316f837dc","repo":"google/gson","slug":"json-must-have-only-one-top-level-value","errorCode":null,"errorMessage":"JSON must have only one top-level value.","messagePattern":"JSON must have only one top-level value\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/stream/JsonWriter.java","lineNumber":810,"sourceCode":"    if (context == NONEMPTY_OBJECT) { // first in object\n      out.write(formattedComma);\n    } else if (context != EMPTY_OBJECT) { // not in an object!\n      throw new IllegalStateException(\"Nesting problem.\");\n    }\n    newline();\n    replaceTop(DANGLING_NAME);\n  }\n\n  /**\n   * Inserts any necessary separators and whitespace before a literal value, inline array, or inline\n   * object. Also adjusts the stack to expect either a closing bracket or another element.\n   */\n  @SuppressWarnings(\"fallthrough\")\n  private void beforeValue() throws IOException {\n    switch (peek()) {\n      case NONEMPTY_DOCUMENT:\n        if (strictness != Strictness.LENIENT) {\n          throw new IllegalStateException(\"JSON must have only one top-level value.\");\n        }\n      // fall-through\n      case EMPTY_DOCUMENT: // first in document\n        replaceTop(NONEMPTY_DOCUMENT);\n        break;\n\n      case EMPTY_ARRAY: // first in array\n        replaceTop(NONEMPTY_ARRAY);\n        newline();\n        break;\n\n      case NONEMPTY_ARRAY: // another in array\n        out.append(formattedComma);\n        newline();\n        break;\n\n      case DANGLING_NAME: // value for name\n        out.append(formattedColon);","sourceCodeStart":792,"sourceCodeEnd":828,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/stream/JsonWriter.java#L792-L828","documentation":"Thrown by JsonWriter.beforeValue() (IllegalStateException) at JsonWriter.java:810 when a value is about to be written and the top-of-stack scope is already NONEMPTY_DOCUMENT, meaning a complete top-level JSON value was already produced. In Strictness.STRICT and LEGACY_STRICT (the default) RFC 8259 forbids more than one top-level value, so a second value/literal/array/object is rejected. Only Strictness.LENIENT falls through to allow concatenated top-level values.","triggerScenarios":"Writing two literals (e.g. value(\"a\"); value(\"b\");) at document top level with default strictness; calling beginArray() after a complete top-level object; reusing a single JsonWriter to emit multiple independent JSON values without wrapping them in an array; loops that write multiple values forgetting to open a container first.","commonSituations":"Streaming multiple records to one writer (log/event streams) where each record is its own JSON object on the same writer; migrating from lenient to default strictness and suddenly hitting the limit; NDJSON-style emission attempted through a single default JsonWriter.","solutions":["Wrap multiple top-level values in a single array: beginArray() ... values ... endArray().","If you genuinely need concatenated top-level values (NDJSON), call writer.setStrictness(Strictness.LENIENT) before writing.","Use a fresh JsonWriter per top-level value instead of reusing one writer across values.","Restructure the loop so each iteration produces exactly one complete document and flushes/closes before the next."],"exampleFix":"// before\nJsonWriter w = new JsonWriter(out); // default LEGACY_STRICT\nw.value(\"first\");\nw.value(\"second\"); // throws 'JSON must have only one top-level value.'\n\n// after (option A: wrap in array)\nJsonWriter w = new JsonWriter(out);\nw.beginArray();\nw.value(\"first\");\nw.value(\"second\");\nw.endArray();\n\n// after (option B: lenient for NDJSON)\nJsonWriter w = new JsonWriter(out);\nw.setStrictness(Strictness.LENIENT);\nw.value(\"first\");\nw.value(\"second\");","handlingStrategy":"validation","validationCode":"// Decide up front: multiple top-level values need an array OR lenient mode.\nJsonWriter w = new JsonWriter(out);\nboolean multipleTopLevel = values.size() > 1;\nif (multipleTopLevel) {\n  // choose ONE strategy:\n  // w.setStrictness(Strictness.LENIENT);  // for NDJSON\n  w.beginArray();              // or wrap\n}","typeGuard":"null","tryCatchPattern":"try {\n  writer.value(first);\n  writer.value(second);\n} catch (IllegalStateException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"only one top-level value\")) {\n    // cannot recover mid-stream safely; this is a design error\n    throw new IllegalStateException(\"Wrap values in an array or use Strictness.LENIENT\", e);\n  }\n  throw e;\n}","preventionTips":["Default strictness is LEGACY_STRICT: design for exactly one top-level value per writer.","For record streams use Strictness.LENIENT explicitly, or a fresh writer per record.","Document the chosen policy at the writer construction site.","Add a test that writes N>1 values to catch regressions when strictness changes."],"tags":["json","gson","streaming","strictness","rfc8259","java"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}