{"record":{"id":"e11cc756c6ea9a05","repo":"apache/cassandra","slug":"length-must-not-be-negative","errorCode":null,"errorMessage":"Length must not be negative","messagePattern":"Length must not be negative","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/io/util/MmappedRegions.java","lineNumber":144,"sourceCode":"        return new MmappedRegions(this);\n    }\n\n    private boolean isCopy()\n    {\n        return copy == null;\n    }\n\n    /**\n     * Extends this collection of mmapped regions up to the provided total length.\n     *\n     * @return {@code true} if new regions have been created\n     */\n    public boolean extend(long length, int chunkSize)\n    {\n        // We cannot enforce length to be a multiple of chunkSize (at the very least the last extend on a file\n        // will not satisfy this), so we hope the caller knows what they are doing.\n        if (length < 0)\n            throw new IllegalArgumentException(\"Length must not be negative\");\n\n        assert !isCopy() : \"Copies cannot be extended\";\n\n        if (length <= state.length)\n            return false;\n\n        int initialRegions = state.last;\n        updateState(length, chunkSize);\n        copy = new State(state);\n        return state.last > initialRegions;\n    }\n\n    /**\n     * Extends this collection of mmapped regions up to the length of the compressed file described by the provided\n     * metadata.\n     *\n     * @return {@code true} if new regions have been created\n     */","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/io/util/MmappedRegions.java#L126-L162","documentation":"MmappedRegions.extend(length, chunkSize) grows the mmap windows to cover the new length; unlike map() it only rejects negative lengths, since growing to exactly 0 is tolerated and extension to a smaller-or-equal length is a no-op. A negative length indicates a caller bug (bad size accounting), so it throws IllegalArgumentException.","triggerScenarios":"Calling extend(length, chunkSize) with length < 0, e.g. from getOrCreate() when a computed region size underflowed, or test/test-code paths (testCopyCannotExtend, checkExtendOnCompressedChunks) passing bad sizes. Also extending after a truncate that produced negative delta math.","commonSituations":"Concurrent truncate-plus-extend races where a file shrinks between size() and extend(); incorrect last-segment size calculations for compressed chunks; arithmetic errors passing (newLength - offset) instead of absolute newLength.","solutions":["Pass the absolute new file length, never a negative delta; clamp with Math.max(0, size) before calling extend","Re-read channel.size() immediately before extend and skip the call if it is <= current length","Fix offset arithmetic that can produce negative values (unsigned/underflow bugs)","Guard against concurrent truncation by checking the returned length and handling races outside extend()"],"exampleFix":"// before\nlong delta = newSize - oldSize;\nregions.extend(delta, chunkSize); // throws when newSize < oldSize\n// after\nlong newSize = Math.max(0, channel.size());\nif (newSize > currentLength) {\n    regions.extend(newSize, chunkSize);\n}","handlingStrategy":"validation","validationCode":"long newSize = Math.max(0, channel.size()); if (newSize < 0 || newSize < regions.getCurrentLength()) return; regions.extend(newSize, chunkSize);","typeGuard":"boolean extendable = length != null && length >= 0;","tryCatchPattern":"try { regions.extend(length, chunkSize); } catch (IllegalArgumentException e) { logger.warn(\"bad extend length\", e); }","preventionTips":["Pass absolute lengths, never deltas","Clamp sizes with Math.max(0, size)","Re-read size at extend time to avoid truncate races"],"tags":["io","mmap","validation"],"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"}