google/gson · error · IllegalStateException

JsonWriter is closed.

Error message

JsonWriter is closed.

What it means

Thrown by JsonWriter.peek() (and flush()) when stackSize == 0, which means close() has already been called and the writer is no longer usable. Any subsequent operation that needs the current scope throws IllegalStateException. The writer is single-use by design.

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 8b8628c656)

Solutions

  1. Do all writing before close(); structure code so close() is the last operation.
  2. Avoid closing the underlying Writer/OutputStream independently; let JsonWriter.close() manage it.
  3. If you need to reopen, create a new JsonWriter over a fresh destination.
  4. Remove redundant flush() calls in finally blocks that may execute after close().

Example fix

// before
try (JsonWriter w = new JsonWriter(new StringWriter())) {
  w.beginObject();
}
w.name("x"); // throws 'JsonWriter is closed.'

// after
JsonWriter w = new JsonWriter(new StringWriter());
w.beginObject();
w.name("x").value(1);
w.endObject();
w.close();
Defensive patterns

Strategy: try-catch

Validate before calling

// Manage lifecycle explicitly; do not write after close
JsonWriter writer = new JsonWriter(dest);
try {
  // all writes here
  writer.beginObject(); writer.endObject();
} finally {
  writer.close();
}
// set a flag if needed:
boolean closed = false;

Try / catch

try {
  writer.flush();
} catch (IllegalStateException e) {
  if (e.getMessage().equals("JsonWriter is closed.")) {
    // writer already closed; nothing to do, or recreate
  } else throw e;
}

Prevention

When it happens

Trigger: Calling any write/flush method on a JsonWriter after close(); e.g. a try-with-resources block that closes the writer, followed by code in a finally or outer block that attempts to write more.

Common situations: Wrapping JsonWriter in try-with-resources and then writing outside the block; closing the underlying Writer/OutputStream separately and then touching the JsonWriter; flushing in a finally that runs after close() on an error path.

Related errors


AI-assisted analysis of google/gson@8b8628c656 (2026-08-04). Data as JSON: /data/errors/7dc22e6f035ca41b.json. Report an issue: GitHub.