{"record":{"id":"1cd5caaaf718ee8c","repo":"apache/cassandra","slug":"stream-can-only-move-forward","errorCode":null,"errorMessage":"stream can only move forward","messagePattern":"stream can only move forward","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/db/streaming/CompressedInputStream.java","lineNumber":98,"sourceCode":"\n        this.input = input;\n        this.checksumType = checksumType;\n        this.validateChecksumChance = validateChecksumChance;\n\n        compressionParams = compressionInfo.parameters();\n        compressedChunks = Iterators.forArray(compressionInfo.chunks());\n        compressedChunk = ByteBuffer.allocateDirect(compressionParams.chunkLength());\n    }\n\n    /**\n     * Invoked when crossing into the next {@link SSTableReader.PartitionPositionBounds} section\n     * in {@link CassandraCompressedStreamReader#read(DataInputPlus)}.\n     * Will skip 1..n compressed chunks of the original sstable.\n     */\n    public void position(long position) throws IOException\n    {\n        if (position < uncompressedChunkPosition + buffer.position())\n            throw new IllegalStateException(\"stream can only move forward\");\n\n        if (position >= uncompressedChunkPosition + buffer.limit())\n        {\n            loadNextChunk();\n            // uncompressedChunkPosition = position - (position % compressionParams.chunkLength())\n            uncompressedChunkPosition = position & -compressionParams.chunkLength();\n        }\n\n        buffer.position(Ints.checkedCast(position - uncompressedChunkPosition));\n    }\n\n    @Override\n    protected void reBuffer() throws IOException\n    {\n        if (uncompressedChunkPosition < 0)\n            throw new IllegalStateException(\"position(long position) wasn't called first\");\n\n        /*","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/db/streaming/CompressedInputStream.java#L80-L116","documentation":"CompressedInputStream.position moves the decompressed stream to a given uncompressed offset during compressed SSTable streaming. Because the stream reads whole compression chunks sequentially, it can only seek forward; attempting to rewind past already-consumed uncompressed data throws IllegalStateException. This is an internal ordering invariant for CassandraCompressedStreamReader.","triggerScenarios":"Calling position(long) with an offset smaller than uncompressedChunkPosition + buffer.position(), i.e. trying to seek backwards within or before the currently buffered chunk.","commonSituations":"Retransmission/retry logic replaying a range that was already read; stream session rollback after a failure; tests simulating random-access reads; custom StreamSession sector handling that requests out-of-order sections.","solutions":["Ensure sections are requested in strictly increasing offset order","Reset/recreate the CompressedInputStream (open a new stream session) if backward seeks are required","Check for retry logic that replays already-read ranges and skip already-consumed sections instead","Verify compression chunk sizes match between sender and receiver"],"exampleFix":"// before\nstream.position(earlierOffset); // throws\n// after\nif (earlierOffset > currentUncompressedPosition()) {\n    stream.position(earlierOffset);\n} else {\n    // reopen stream or skip handling\n}","handlingStrategy":"validation","validationCode":"if (targetPosition < lastPosition) throw new IllegalArgumentException(\"backward seek not allowed\");","typeGuard":"boolean canSeek = pos -> pos >= stream.currentUncompressedPosition();","tryCatchPattern":"try { stream.position(pos); } catch (IllegalStateException e) { reopenStream(pos); }","preventionTips":["Request stream sections in ascending offset order","Never replay ranges in retry logic; skip already-read data","Keep one stream instance per session; recreate on rewind"],"tags":["streaming","compression","seek","illegal-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}