{"record":{"id":"d25124d3f196c51e","repo":"apache/cassandra","slug":"ranges-supplied-to-sstablesimplescanner-must-be-no","errorCode":null,"errorMessage":"Ranges supplied to SSTableSimpleScanner must be non-overlapping and in ascending order.","messagePattern":"Ranges supplied to SSTableSimpleScanner must be non-overlapping and in ascending order\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/io/sstable/format/SSTableSimpleScanner.java","lineNumber":182,"sourceCode":"\n        if (dfile.getFilePointer() < currentEndPosition)\n            return true;\n\n        return advanceRange();\n    }\n\n    boolean advanceRange()\n    {\n        try\n        {\n            if (!rangeIterator.hasNext())\n                return false;\n\n            bytesScannedInPreviousRanges += currentEndPosition - currentStartPosition;\n\n            PartitionPositionBounds nextRange = rangeIterator.next();\n            if (currentEndPosition > nextRange.lowerPosition)\n                throw new IllegalArgumentException(\"Ranges supplied to SSTableSimpleScanner must be non-overlapping and in ascending order.\");\n\n            currentEndPosition = nextRange.upperPosition;\n            currentStartPosition = nextRange.lowerPosition;\n            dfile.seek(currentStartPosition);\n            return true;\n        }\n        catch (CorruptSSTableException e)\n        {\n            sstable.markSuspect();\n            throw e;\n        }\n        catch (IOError e)\n        {\n            if (e.getCause() instanceof IOException)\n            {\n                sstable.markSuspect();\n                throw new CorruptSSTableException((Exception)e.getCause(), sstable.getFilename());\n            }","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/io/sstable/format/SSTableSimpleScanner.java#L164-L200","documentation":"SSTableSimpleScanner's advanceRange() walks a caller-supplied set of key ranges mapped to file positions; it requires them to be non-overlapping and in ascending order of position. When the next range's lower position is less than the current range's end position, it throws IllegalArgumentException because scanning would double-read or rewind within the data file.","triggerScenarios":"Constructing SSTableSimpleScanner with a collection of ranges that overlap (currentEndPosition > nextRange.lowerPosition) or are out of ascending order; the failure surfaces on advanceRange() when hasNext() advances past the first range.","commonSituations":"Custom bulk-read/sstable-scanning tools computing ranges from faulty logic; intersecting token ranges from duplicated token assignments; hand-built range lists not sorted before use.","solutions":["Sort the ranges in ascending order before constructing the scanner","Merge/eliminate overlapping ranges into disjoint segments before passing them in","Validate the range list programmatically prior to scanner creation (assert non-overlap)","Regenerate the ranges from the correct source (e.g. proper token range splitting)"],"exampleFix":"// before: raw possibly overlapping ranges\nnew SSTableSimpleScanner(sstable, ranges);\n// after: sort and merge first\nList<PartitionPositionBounds> fixed = mergeOverlapping(\n    ranges.stream().sorted(Comparator.comparingLong(r -> r.lowerPosition)).collect(Collectors.toList()));\nnew SSTableSimpleScanner(sstable, fixed);","handlingStrategy":"validation","validationCode":"// validate ranges before constructing the scanner\nlong prevEnd = -1;\nfor (PartitionPositionBounds r : ranges) {\n    if (r.lowerPosition <= prevEnd) throw new IllegalArgumentException(\"overlapping/out-of-order ranges\");\n    prevEnd = r.upperPosition;\n}","typeGuard":null,"tryCatchPattern":"try { scanner.hasNext() / scanner.next(); }\ncatch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"non-overlapping and in ascending order\")) {\n        ranges = sortAndMerge(ranges); // rebuild scanner with fixed ranges\n    } else throw e;\n}","preventionTips":["Sort and merge ranges before creating SSTableSimpleScanner","Derive ranges from non-overlapping token range splitting logic","Unit-test range generation code for overlap conditions","Assert range ordering in tooling before scanning"],"tags":["illegal-argument","scanner","ranges"],"backgroundTag":"invalid-argument-value","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}