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

  1. Finish all writes before close(); do not write after.
  2. Do not reuse a JsonWriter across streams; create a new one per output.
  3. Move close() to the outermost scope so nothing writes after it.
  4. 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

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


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)