{"record":{"id":"315b97d013d315ef","repo":"apache/cassandra","slug":"clustering-keys-must-be-in-ascending-lexographical","errorCode":null,"errorMessage":"Clustering keys must be in ascending lexographical order","messagePattern":"Clustering keys must be in ascending lexographical order","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/index/sai/disk/v1/keystore/KeyStoreWriter.java","lineNumber":134,"sourceCode":"    }\n\n    /**\n     * Appends a key at the end of the sequence.\n     *\n     * @throws IOException if write to disk fails\n     * @throws IllegalArgumentException if the key is not greater than the previous added key\n     */\n    public void add(final @Nonnull ByteComparable key) throws IOException\n    {\n        tempKey.clear();\n        copyBytes(key, tempKey);\n\n        BytesRef keyRef = tempKey.get();\n\n        if (clustering && inPartition)\n        {\n            if (compareKeys(keyRef, prevKey.get()) <= 0)\n                throw new IllegalArgumentException(\"Clustering keys must be in ascending lexographical order\");\n        }\n\n        inPartition = true;\n\n        writeKey(keyRef);\n\n        maxKeyLength = Math.max(maxKeyLength, keyRef.length);\n\n        BytesRefBuilder temp = this.tempKey;\n        this.tempKey = this.prevKey;\n        this.prevKey = temp;\n\n        pointId++;\n    }\n\n    private void writeKey(BytesRef key) throws IOException\n    {\n        if ((pointId & blockMask) == 0)","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/index/sai/disk/v1/keystore/KeyStoreWriter.java#L116-L152","documentation":"KeyStoreWriter.add() requires that, when writing clustering-key-scope keys (clustering && inPartition), each BytesRef key is strictly greater than the previous one. Keys are written into a shared trie/blocks structure that relies on sorted order; an out-of-order key would make lookups and prefix decoding incorrect. The message (note the 'lexographical' typo) is thrown as IllegalArgumentException.","triggerScenarios":"Adding clustering keys where compareKeys(keyRef, prevKey) <= 0, i.e. equal or descending order, during segment flush of a partition-scoped SAI key store.","commonSituations":"Internal SAI bug or corrupted memtable ordering during flush; developers hitting this are usually instrumenting KeyStoreWriter directly with unsorted keys.","solutions":["Ensure keys are added in ascending order — sort the batch before calling add().","If duplicates are expected, skip keys equal to the previous key before writing.","If seen during normal flush, it indicates internal corruption — report with the Cassandra version and rebuild the index."],"exampleFix":"// before\nwriter.add(key2);\nwriter.add(key1); // throws if key1 <= key2\n// after\nkeys.sort(comparator);\nfor (BytesRef k : keys) writer.add(k);","handlingStrategy":"validation","validationCode":"if (prevKey != null && compareKeys(nextKey, prevKey) <= 0) skipOrSort(nextKey);","typeGuard":null,"tryCatchPattern":"try { writer.add(keyRef); } catch (IllegalArgumentException e) { log.error(\"Unsorted clustering key\", e); throw e; }","preventionTips":["Sort keys (or use an already-sorted source iterator) before writing.","Skip duplicates equal to the previous key."],"tags":["cassandra","sai","ordering","internal-invariant"],"backgroundTag":"internal-invariant-violation","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"}