google/gson · error · IllegalStateException
JsonWriter is closed.
Error message
JsonWriter is closed.
What it means
Thrown by JsonWriter.peek() (JsonWriter.java:480-483) when stackSize == 0, which happens after close() sets stackSize to 0 (JsonWriter.java:719-727). Because every write operation calls peek() to inspect the current scope, any write or name() call after close triggers this IllegalStateException. It prevents writes to a writer whose underlying Writer has been released.
Solutions
- Finish all writes before close(); do not write after.
- Do not reuse a JsonWriter across streams; create a new one per output.
- Move close() to the outermost scope so nothing writes after it.
- Buffer the full document in memory and write it once if you need post-close access.
Example fix
// before
try (JsonWriter w = new JsonWriter(out)) {
w.beginObject().name("a").value(1).endObject();
}
w.flush(); // throws: writer is closed
// after
try (JsonWriter w = new JsonWriter(out)) {
w.beginObject().name("a").value(1).endObject();
w.flush();
} Defensive patterns
Strategy: validation
Validate before calling
try (JsonWriter w = new JsonWriter(out)) {
w.beginObject().name("a").value(1).endObject();
w.flush();
}
// nothing writes after this block Type guard
// JsonWriter has no isOpen(); track in a wrapper.
class SafeJsonWriter {
private final JsonWriter w;
private boolean closed;
boolean isOpen() { return !closed; }
public void close() throws IOException { w.close(); closed = true; }
} Try / catch
try {
w.value(1);
} catch (IllegalStateException e) {
if (e.getMessage().contains("closed")) return; // or reopen a new writer
throw e;
} Prevention
- Close exactly once, at the outermost scope, after all writes.
- Do not pool/cache JsonWriter instances.
- Ensure framework shutdown hooks do not write after close.
When it happens
Trigger: Calling any write method, name(), begin*/end*, or value() after writer.close(); using a JsonWriter in a try-with-resources and writing in a finally or callback that runs post-close; reusing a cached writer instance that was closed.
Common situations: try-with-resources that closes the writer before a deferred flush/write; pooling/caching JsonWriter instances without resetting state; helper methods that close the writer and then the caller tries to append more.
Related errors
- JsonReader is closed
- Already wrote a name, expecting a value.
- Dangling name
- Nesting problem.
- Numeric values must be finite, but was
AI-assisted analysis of google/gson@310ac341f2 (2026-08-10).
Data as JSON: /api/errors/7dc22e6f035ca41b.
Report an issue: GitHub.
Appendix: source
Thrown at gson/src/main/java/com/google/gson/stream/JsonWriter.java:482
stackSize--;
if (context == nonempty) {
newline();
}
out.write(closeBracket);
return this;
}
private void push(int newTop) {
if (stackSize == stack.length) {
stack = Arrays.copyOf(stack, stackSize * 2);
}
stack[stackSize++] = newTop;
}
/** Returns the value on the top of the stack. */
private int peek() {
if (stackSize == 0) {
throw new IllegalStateException("JsonWriter is closed.");
}
return stack[stackSize - 1];
}
/** Replace the value on the top of the stack with the given value. */
private void replaceTop(int topOfStack) {
stack[stackSize - 1] = topOfStack;
}
/**
* Encodes the property name.
*
* @param name the name of the forthcoming value. May not be {@code null}.
* @return this writer.
*/
@CanIgnoreReturnValue
public JsonWriter name(String name) throws IOException {
Objects.requireNonNull(name, "name == null");View on GitHub (pinned to 310ac341f2)