apache/iceberg · error · IllegalStateException

HashWriter is closed.

Error message

HashWriter is closed.

What it means

HashWriter.ensureNotClosed() throws IllegalStateException once the writer has finished hashing (after getHash() closes it). A HashWriter is single-use: after digest retrieval it cannot accept writes or produce another hash.

Solutions

  1. Create a new HashWriter for each hash computation
  2. Read the digest once and store the result instead of calling getHash() repeatedly
  3. Refactor code to accumulate all writes before finalizing

Example fix

// before
hashWriter.write(data);
byte[] h1 = hashWriter.getHash();
byte[] h2 = hashWriter.getHash(); // throws
// after
hashWriter.write(data);
byte[] hash = hashWriter.getHash();
byte[] h1 = hash, h2 = hash;
Defensive patterns

Strategy: try-catch

Validate before calling

if (hashWriterClosed) throw new IllegalStateException("create a new HashWriter");

Try / catch

try { byte[] h = hashWriter.getHash(); } catch (IllegalStateException e) { hashWriter = new HashWriter(algorithm); /* redo */ }

Prevention

When it happens

Trigger: Calling write(byte[], int, int) or getHash() after a previous getHash() call set isClosed=true.

Common situations: Reusing a cached HashWriter instance across rows or files; calling getHash() twice to read the digest incrementally; resuming an aborted write after finalization.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/1f1b08f256e15571. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/util/HashWriter.java:75

  public void close() throws IOException {
    isClosed = true;
  }

  /**
   * Calculates the final hash value. The underlying digest will be reset thus subsequent getHash()
   * calls are not permitted.
   *
   * @return bytes of final hash value
   */
  public byte[] getHash() {
    ensureNotClosed();
    isClosed = true;
    return digest.digest();
  }

  private void ensureNotClosed() {
    if (isClosed) {
      throw new IllegalStateException("HashWriter is closed.");
    }
  }
}

View on GitHub (pinned to 86d9c8fc54)