google/gson · error · IllegalStateException
JSON must have only one top-level value.
Error message
JSON must have only one top-level value.
What it means
Thrown by JsonWriter.beforeValue() when strictness is not LENIENT (default LEGACY_STRICT) and a value is written after a top-level value has already completed (peek() == NONEMPTY_DOCUMENT). RFC 8259 permits exactly one top-level JSON value, so a compliant writer rejects the second. LENIENT mode permits multiple concatenated top-level values (useful for JSON streaming/NDJSON-like protocols).
Source
Thrown at gson/src/main/java/com/google/gson/stream/JsonWriter.java:810
if (context == NONEMPTY_OBJECT) { // first in object
out.write(formattedComma);
} else if (context != EMPTY_OBJECT) { // not in an object!
throw new IllegalStateException("Nesting problem.");
}
newline();
replaceTop(DANGLING_NAME);
}
/**
* Inserts any necessary separators and whitespace before a literal value, inline array, or inline
* object. Also adjusts the stack to expect either a closing bracket or another element.
*/
@SuppressWarnings("fallthrough")
private void beforeValue() throws IOException {
switch (peek()) {
case NONEMPTY_DOCUMENT:
if (strictness != Strictness.LENIENT) {
throw new IllegalStateException("JSON must have only one top-level value.");
}
// fall-through
case EMPTY_DOCUMENT: // first in document
replaceTop(NONEMPTY_DOCUMENT);
break;
case EMPTY_ARRAY: // first in array
replaceTop(NONEMPTY_ARRAY);
newline();
break;
case NONEMPTY_ARRAY: // another in array
out.append(formattedComma);
newline();
break;
case DANGLING_NAME: // value for name
out.append(formattedColon);View on GitHub (pinned to 8b8628c656)
Solutions
- Wrap multiple top-level values in an array: beginArray() ... values ... endArray().
- Use a fresh JsonWriter per top-level value (typical for NDJSON where each line is its own document).
- Call writer.setStrictness(Strictness.LENIENT) if you genuinely want concatenated top-level values in one stream.
- Restructure so there is exactly one root value, e.g. an object containing the additional data as fields.
Example fix
// before (default LEGACY_STRICT)
writer.beginObject().name("a").value(1).endObject();
writer.beginObject().name("b").value(2).endObject(); // throws
// after: one writer per document (NDJSON)
for (Item i : items) {
try (JsonWriter w = jsonWriter(out)) {
writeItem(w, i);
}
} Defensive patterns
Strategy: validation
Validate before calling
// One value per writer in strict mode; create a new writer per document
public void writeNdJson(List<String> docs, Writer sink) throws IOException {
for (String doc : docs) {
// each line is its own complete document -> its own writer
try (JsonWriter w = jsonWriter(new BufferedWriter(sink))) {
writeDoc(w, doc);
w.flush();
}
sink.write('\n');
}
} Type guard
// True if the writer may legally accept another top-level value
public boolean canAcceptTopLevel(boolean firstValueWritten, Strictness s) {
return !firstValueWritten || s == Strictness.LENIENT;
} Try / catch
try {
writer.beginObject();
} catch (IllegalStateException e) {
// 'JSON must have only one top-level value.' -> start a fresh writer
writer.close();
JsonWriter fresh = jsonWriter(out);
fresh.setStrictness(Strictness.LENIENT); // if concatenated docs are intended
fresh.beginObject();
} Prevention
- Treat one JsonWriter as one JSON document; create a new writer per document for streaming.
- If you need multiple concatenated top-level values, call setStrictness(Strictness.LENIENT) explicitly and document the contract.
- Wrap logically grouped data in an enclosing array/object instead of emitting several roots.
- Assert firstValueWritten state in your serializer to fail fast on accidental reuse.
When it happens
Trigger: Calling writer.value(...) / beginObject() / beginArray() a second time after the first top-level value was fully written and its container (if any) closed, while in LEGACY_STRICT or STRICT. Reusing a single JsonWriter to emit several independent JSON objects back-to-back; writing a value, then writing another without an enclosing array.
Common situations: Building NDJSON / JSON Lines over one writer (default mode forbids it); request-scoped JsonWriter reused for multiple payload fragments; serializers that write a status object then try to append a second; test harness writing multiple JSON values to one StringWriter.
Related errors
- Numeric values must be finite, but was " + string
- String created by " + numberClass + " is not a valid JSON nu
- JSON forbids NaN and infinities: {value}
- Incomplete document
- ${message}${locationString()} See ${TroubleshootingGuide.cre
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/579fd59316f837dc.json.
Report an issue: GitHub.