apache/cassandra · error · IllegalStateException
Attempted to seek in a closed RAR
Error message
Attempted to seek in a closed RAR
What it means
RandomAccessReader throws IllegalStateException from seek() when the reader has already been closed (buffer == null). Once close() releases the internal buffer, any further positioning or read operation is invalid because there is no channel/buffer to seek within.
Solutions
- Ensure the reader's lifetime covers all uses — do not close while iterators depend on it
- Check isClosed() (or null buffer) before seeking and reopen if needed
- Restructure try-with-resources so the iteration happens inside the scope
- Fix double-close/reuse bugs: obtain a fresh RandomAccessReader via createReader instead of reusing closed handles
Example fix
// before
try (RandomAccessReader reader = RandomAccessReader.open(file)) {
scheduleAsyncIteration(reader); // reader closed before iteration runs
}
// after
RandomAccessReader reader = RandomAccessReader.open(file);
try {
iterateKeys(reader);
} finally {
CloseableIterator<?> it = iterator;
if (it != null) it.close();
reader.close();
} Defensive patterns
Strategy: try-catch
Validate before calling
if (reader.isClosed()) { reader = RandomAccessReader.open(file); } reader.seek(pos); Type guard
boolean open = reader != null && !reader.isClosed();
Try / catch
try { reader.seek(pos); } catch (IllegalStateException e) { /* reopen reader or abort iteration */ } Prevention
- Keep reader open for the entire iteration scope
- Avoid sharing readers across async lifecycles
- Use try-with-resources so close happens after all reads
When it happens
Trigger: Calling seek() after close() — typically a use-after-close bug: a reader closed in a finally block or by an earlier exception path, then still referenced by an iterator (keyIterator/keyReader), a sync-marker scan (readSyncMarker), or reset()/skipBytes() invoked on a stale handle.
Common situations: Prematurely closing a shared reader while another component still iterates it; double-close followed by reuse; returning a reader from a cache after its owner closed it; try-with-resources closing a reader that an enclosing iterator still uses.
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
- Attempted skipBytes() on a closed RAR
- new position should not be negative
- Unable to seek to position
- Ballot file corrupted
- Can't open %r for reading
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/97b9ecdfe6e1b2d3.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/io/util/RandomAccessReader.java:224
*/
private static class BufferedRandomAccessFileMark implements DataPosition
{
final long pointer;
private BufferedRandomAccessFileMark(long pointer)
{
this.pointer = pointer;
}
}
@Override
public void seek(long newPosition)
{
if (newPosition < 0)
throw new IllegalArgumentException("new position should not be negative");
if (buffer == null)
throw new IllegalStateException("Attempted to seek in a closed RAR");
long bufferOffset = bufferHolderOffset;
if (newPosition >= bufferOffset && newPosition < bufferOffset + buffer.limit())
{
buffer.position((int) (newPosition - bufferOffset));
return;
}
if (newPosition > length())
throw new IllegalArgumentException(String.format("Unable to seek to position %d in %s (%d bytes) in read-only mode",
newPosition, getPath(), length()));
reBufferAt(newPosition);
}
@Override
public int skipBytes(int n) throws IOException
{
if (n <= 0)View on GitHub (pinned to 88fd0f6a0e)