{"record":{"id":"163ae5cc5f1d9431","repo":"apache/cassandra","slug":"postings-must-be-sorted-ascending-got-s-after","errorCode":null,"errorMessage":"Postings must be sorted ascending, got [%s] after [%s]","messagePattern":"Postings must be sorted ascending, got \\[(.+?)\\] after \\[(.+?)\\]","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/index/sai/disk/v1/postings/PostingsWriter.java","lineNumber":217,"sourceCode":"        return summaryOffset;\n    }\n\n    public long getTotalPostings()\n    {\n        return totalPostings;\n    }\n\n    private void writePosting(long posting) throws IOException\n    {\n        if (lastPosting == Long.MIN_VALUE)\n        {\n            firstPosting = posting;\n            deltaBuffer[bufferUpto++] = 0;\n        }\n        else\n        {\n            if (posting < lastPosting)\n                throw new IllegalArgumentException(String.format(POSTINGS_MUST_BE_SORTED_ERROR_MSG, posting, lastPosting));\n            long delta = posting - lastPosting;\n            maxDelta = max(maxDelta, delta);\n            deltaBuffer[bufferUpto++] = delta;\n        }\n        lastPosting = posting;\n\n        if (bufferUpto == blockSize)\n        {\n            addBlockToSkipTable();\n            writePostingsBlock();\n            resetBlockCounters();\n        }\n    }\n\n    private void finish() throws IOException\n    {\n        if (bufferUpto > 0)\n        {","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/index/sai/disk/v1/postings/PostingsWriter.java#L199-L235","documentation":"PostingsWriter.writePosting() enforces that postings (rowids) arrive in strictly non-decreasing order, because the on-disk format stores delta-encoded values. A posting smaller than the previous one would produce a negative delta that cannot be encoded, so it fails fast with IllegalArgumentException.","triggerScenarios":"Calling writePosting (via write()) with posting < lastPosting, i.e. feeding rowids out of order during segment flush of an SAI posting list.","commonSituations":"Internal SAI bug where the row-id source (partition/row iterator) is not sorted; developers writing custom key-range iterators or replaying unsorted buffers see this.","solutions":["Ensure the rowid source is sorted ascending before writing postings.","Deduplicate the caller's iteration order (e.g. sort per-partition row ids).","If encountered during normal flush, it's an internal invariant breach — gather logs/version and report; rebuild the index in the meantime."],"exampleFix":"// before\nfor (long id : unsortedIds) writer.writePosting(id);\n// after\nArrays.sort(ids);\nfor (long id : ids) writer.writePosting(id);","handlingStrategy":"validation","validationCode":"for (int i = 1; i < ids.length; i++) if (ids[i] < ids[i-1]) throw new AssertionError(\"unsorted rowids\");","typeGuard":null,"tryCatchPattern":"try { writer.writePosting(p); } catch (IllegalArgumentException e) { log.error(\"Posting order violated\", e); throw e; }","preventionTips":["Always source postings from a sorted rowid iterator.","Add debug assertions on input ordering before write loops."],"tags":["cassandra","sai","ordering","delta-encoding"],"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"}