apache/cassandra · error · IllegalStateException
[%s] Writer already finished!
Error message
[%s] Writer already finished!
What it means
AbstractBlockPackedWriter guards against writing to a block-packed writer after finish() has been called. Once finished, the block footer/counts are flushed to the IndexOutput, so any further add() (or a second finish()) would corrupt the written file. The exception names the underlying index output file to make the offending component identifiable.
Source
Thrown at src/java/org/apache/cassandra/index/sai/disk/v1/bitpack/AbstractBlockPackedWriter.java:122
while ((i & ~0x7FL) != 0L && k++ < 8)
{
out.writeByte((byte) ((i & 0x7FL) | 0x80L));
i >>>= 7;
}
out.writeByte((byte) i);
}
private void flush() throws IOException
{
flushBlock();
blockIndex = 0;
}
private void checkNotFinished()
{
if (finished)
{
throw new IllegalStateException(String.format("[%s] Writer already finished!", indexOutput.getName()));
}
}
}
View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Do not call add() after finish(); restructure the write loop so all values are added before finish().
- Guard call sites with a finished flag or assert !writer.isFinished() before adding.
- If triggered by an internal flush bug, verify against the Cassandra version and check for known SAI segment-builder fixes; upgrade.
Example fix
// before writer.add(value); writer.finish(); writer.add(more); // throws // after writer.add(value); writer.add(more); writer.finish();
Defensive patterns
Strategy: type-guard
Type guard
boolean canWrite(AbstractBlockPackedWriter w) { return !w.isFinished(); } Try / catch
try { writer.add(v); } catch (IllegalStateException e) { log.error("Write after finish", e); throw e; } Prevention
- Centralize writer lifecycle: one code path owns add/finish ordering.
- Assert writer not finished in debug builds before add().
When it happens
Trigger: Calling add() after finish() on the same writer, or calling finish() twice; happens when a segment write loop keeps posting rows after the writer was closed out, e.g. double-flush in a segment builder.
Common situations: Bugs in SAI segment builders that finish writers early on empty segments or on flush/replay paths, then attempt more writes; internal Cassandra code, not user-triggered directly.
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
- %s function resource has no function name
- Root-level resource can't have a parent
- ROOT data resource has no keyspace
- QueryCancelledException(readCommand)
- Storage-attached index does not support the following IParti
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/b3d503879a00231d.
Report an issue: GitHub.