google/gson · error · IllegalStateException
JsonReader is closed
Error message
JsonReader is closed
What it means
Thrown by JsonReader.doPeek (and any operation that triggers it) once the reader's scope stack top is JsonScope.CLOSED, i.e. after close() has been called. The reader is single-use; continuing to read from it is a programmer error, surfaced as IllegalStateException rather than silently returning stale data.
Source
Thrown at gson/src/main/java/com/google/gson/stream/JsonReader.java:674
default:
throw syntaxError("Expected ':'");
}
} else if (peekStack == JsonScope.EMPTY_DOCUMENT) {
if (strictness == Strictness.LENIENT) {
consumeNonExecutePrefix();
}
stack[stackSize - 1] = JsonScope.NONEMPTY_DOCUMENT;
} else if (peekStack == JsonScope.NONEMPTY_DOCUMENT) {
int c = nextNonWhitespace(false);
if (c == -1) {
peeked = PEEKED_EOF;
return peeked;
} else {
checkLenient();
pos--;
}
} else if (peekStack == JsonScope.CLOSED) {
throw new IllegalStateException("JsonReader is closed");
}
int c = nextNonWhitespace(true);
switch (c) {
case ']':
if (peekStack == JsonScope.EMPTY_ARRAY) {
peeked = PEEKED_END_ARRAY;
return peeked;
}
// fall-through to handle ",]"
case ';':
case ',':
// In lenient mode, a 0-length literal in an array means 'null'.
if (peekStack == JsonScope.EMPTY_ARRAY || peekStack == JsonScope.NONEMPTY_ARRAY) {
checkLenient();
pos--;
peeked = PEEKED_NULL;
return peeked;View on GitHub (pinned to 8b8628c656)
Solutions
- Do not use a JsonReader after close(); perform all reads inside the same scope before closing.
- Avoid try-with-resources if the reader must outlive the current method; manage its lifecycle explicitly and close exactly once.
- If re-parsing is needed, create a fresh JsonReader from the original source.
- Guard with a boolean isOpen flag in your wrapper to fail with a clearer message.
Example fix
// before
try (JsonReader reader = new JsonReader(new StringReader(json))) {
// ...
}
reader.peek(); // throws 'JsonReader is closed'
// after
JsonReader reader = new JsonReader(new StringReader(json));
try {
// ... all reads here
} finally {
reader.close();
} Defensive patterns
Strategy: try-catch
Validate before calling
// Track closed state in a wrapper
JsonReader reader = ...;
boolean closed = false;
// single source of close():
void closeReader() throws IOException { reader.close(); closed = true; }
// guard reads:
void safePeek() throws IOException {
if (closed) throw new IllegalStateException("reader already closed");
reader.peek();
} Try / catch
try {
reader.peek();
} catch (IllegalStateException e) {
if (e.getMessage().equals("JsonReader is closed")) {
// recreate reader or report upstream; do not silently ignore
} else throw e;
} Prevention
- Perform all reads within the lifecycle scope that owns the reader; close exactly once at the end.
- Avoid returning a JsonReader from a try-with-resources block.
- Keep reader usage in a single method where possible.
- Add a closed-flag wrapper if the reader must be shared across methods.
When it happens
Trigger: Calling any of peek(), hasNext(), beginObject(), nextString(), etc. on a JsonReader instance after close() has been invoked (e.g. via try-with-resources that auto-closes, then a later read attempt).
Common situations: Storing the JsonReader in a field and closing it in one method while another method still reads; returning a reader from a try-with-resources block; wrapping parsing logic where the cleanup path closes early on an exception but processing continues.
Related errors
- JsonWriter is closed.
- Incomplete document
- JsonReader is closed
- Incomplete document
- Invalid nesting limit: " + limit
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/b066dcbdcf8b1544.json.
Report an issue: GitHub.