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

  1. Ensure the reader's lifetime covers all uses — do not close while iterators depend on it
  2. Check isClosed() (or null buffer) before seeking and reopen if needed
  3. Restructure try-with-resources so the iteration happens inside the scope
  4. 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

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


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)