{"record":{"id":"80e50bca760dcfd5","repo":"apache/cassandra","slug":"seeking-to-a-partition-at-position-did-not-lan","errorCode":null,"errorMessage":"Seeking to a partition at: ${position} did not land after an end-of-partition marker; found 0x${marker}","messagePattern":"Seeking to a partition at: (.+?) did not land after an end-of-partition marker; found 0x(.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/io/sstable/SSTableCursorReader.java","lineNumber":725,"sourceCode":"    /**\n     * Seeks to the start of a partition. Every partition but the file's first follows an\n     * end-of-partition marker, and reading that byte leaves the reader at the partition start.\n     */\n    private void seekPartition(long position) throws IOException\n    {\n        if (position == 0)\n        {\n            if (dataReader.getPosition() != 0)\n                dataReader.seek(0);\n            return;\n        }\n        dataReader.seek(position - 1);\n        // The exact byte, not isEndOfPartition, which is (b & 1) != 0 and so accepts 128 of the 256\n        // values. The writer emits END_OF_PARTITION alone for this marker, so the stronger test\n        // costs nothing and rejects a mis-sized bound that happens to land on an odd byte.\n        int marker = dataReader.readUnsignedByte();\n        if (marker != UnfilteredSerializer.END_OF_PARTITION)\n            throw new IOException(\"Seeking to a partition at: \" + position + \" did not land after an end-of-partition marker; found 0x\"\n                                  + Integer.toHexString(marker));\n    }\n\n    // struct partition {\n    //   struct partition_header header\n    //   optional<struct row> row\n    //   struct unfiltered unfiltereds[];\n    //};\n    public int readPartitionHeader(PartitionDescriptor header)\n    {\n        if (state != PARTITION_START) throw new IllegalStateException();\n        resetOnPartitionStart();\n        try\n        {\n            header.load(dataReader, deletionTimeSerializer);\n            return checkNextFlagsAfterPartitionStart(false);\n        }\n        catch (Exception e)","sourceCodeStart":707,"sourceCodeEnd":743,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/io/sstable/SSTableCursorReader.java#L707-L743","documentation":"When seeking to a partition start, SSTableCursorReader reads the byte immediately before the target position and requires the exact END_OF_PARTITION marker byte (a stricter test than isEndOfPartition's bit check). Any other byte means the seek position is not a true partition boundary, indicating corrupt bounds or a corrupt data file.","triggerScenarios":"Seeking to a partition start offset from bounds/index metadata that does not sit exactly one byte past an end-of-partition marker — mis-sized bounds landing one byte off, or Data.db corruption.","commonSituations":"Corrupted data files after disk failures; hand-edited or wrongly generated partition bounds; truncated Data.db shifting offsets; buggy tools computing partition start positions.","solutions":["Run nodetool verify / sstableverify on the sstable to confirm corruption.","Run nodetool scrub (sstablescrub) to repair or quarantine the corrupt sstable.","Restore the sstable from backup and run nodetool repair to re-replicate data.","If offsets come from custom tooling, fix bound computation to land exactly one byte past the END_OF_PARTITION marker."],"exampleFix":"// before\nreader.seekToPartition(bounds.lowerPosition);\n// after\ntry {\n    reader.seekToPartition(bounds.lowerPosition);\n} catch (IOException e) {\n    throw new CorruptSSTableException(e, ssTableReader.getFilename()); // treat as corruption\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    cursor.seekToPartition(pos);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"end-of-partition marker\"))\n        throw new CorruptSSTableException(e, filename); // route to scrub/verify\n    throw e;\n}","preventionTips":["Run periodic nodetool verify to detect data-file corruption early.","Generate partition bounds only from tools that validate end-of-partition markers.","Verify digests after copying sstables between nodes.","Avoid manually truncating Data.db."],"tags":["sstable","corruption","io"],"backgroundTag":"checksum-mismatch","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}