apache/cassandra · error · IOException

Attempted skipBytes() on a closed RAR

Error message

Attempted skipBytes() on a closed RAR

What it means

RandomAccessReader.skipBytes(n) throws IOException when the reader's buffer is null, i.e. the reader was closed. Like the seek-after-close error, this is a use-after-close bug, but it surfaces as IOException because skipBytes implements the InputStream contract.

Solutions

  1. Ensure the reader stays open until all partition/entry reads (including skipEntryRemainder) complete
  2. Check isClosed() before calling skipBytes and abort the read loop if closed
  3. Fix control flow so a mid-read exception does not trigger both close and further skip calls
  4. Use a single owner/thread for the reader lifecycle to avoid premature closes

Example fix

// before
} finally {
    reader.close();
}
skipEntryRemainder(reader); // IOException: closed RAR
// after
try {
    readEntry(reader);
    skipEntryRemainder(reader);
} finally {
    reader.close();
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (reader.isClosed()) return; // or abort read loop
reader.skipBytes(n);

Type guard

boolean canSkip = reader != null && !reader.isClosed();

Try / catch

try { reader.skipBytes(n); } catch (IOException e) { /* abort entry processing; reader was closed */ }

Prevention

When it happens

Trigger: Calling skipBytes() after close() — from skipEntryRemainder, readPartition/readUnfiltered loops, or tests, when a reader handle outlives its owner's close (e.g. an iterator closed upstream but the partition-deserialization loop keeps skipping).

Common situations: Closing a reader while a row/partition deserialization is still in progress; exception paths that close the reader mid-read and then a finally block attempts to skip remaining entry bytes; shared reader handles across threads where one closes early.

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/5fa3b0430df9c390. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/io/util/RandomAccessReader.java:245

        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)
            return 0;
        if (buffer == null)
            throw new IOException("Attempted skipBytes() on a closed RAR");
        long current = current();
        long newPosition = Math.min(current + n, length());
        n = (int)(newPosition - current);
        seek(newPosition);
        return n;
    }

    /**
     * Reads a line of text form the current position in this file. A line is
     * represented by zero or more characters followed by {@code '\n'}, {@code
     * '\r'}, {@code "\r\n"} or the end of file marker. The string does not
     * include the line terminating sequence.
     * <p>
     * Blocks until a line terminating sequence has been read, the end of the
     * file is reached or an exception is thrown.
     * </p>
     * @return the contents of the line or {@code null} if no characters have
     * been read before the end of the file has been reached.

View on GitHub (pinned to 88fd0f6a0e)