{"record":{"id":"e67a1cdf0bc29f84","repo":"apache/pulsar","slug":"toindex-0-toindex","errorCode":null,"errorMessage":"toIndex < 0: <toIndex>","messagePattern":"toIndex < 0: <toIndex>","errorType":"validation","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"pulsar-common/src/main/java/org/apache/pulsar/common/util/collections/BitSetRecyclable.java","lineNumber":341,"sourceCode":"     * possibly using recalculateWordsInUse().\n     * @param wordIndex the index to be accommodated.\n     */\n    private void expandTo(int wordIndex) {\n        int wordsRequired = wordIndex+1;\n        if (wordsInUse < wordsRequired) {\n            ensureCapacity(wordsRequired);\n            wordsInUse = wordsRequired;\n        }\n    }\n\n    /**\n     * Checks that fromIndex ... toIndex is a valid range of bit indices.\n     */\n    private static void checkRange(int fromIndex, int toIndex) {\n        if (fromIndex < 0)\n            throw new IndexOutOfBoundsException(\"fromIndex < 0: \" + fromIndex);\n        if (toIndex < 0)\n            throw new IndexOutOfBoundsException(\"toIndex < 0: \" + toIndex);\n        if (fromIndex > toIndex)\n            throw new IndexOutOfBoundsException(\"fromIndex: \" + fromIndex +\n                \" > toIndex: \" + toIndex);\n    }\n\n    /**\n     * Sets the bit at the specified index to the complement of its\n     * current value.\n     *\n     * @param  bitIndex the index of the bit to flip\n     * @throws IndexOutOfBoundsException if the specified index is negative\n     * @since  1.4\n     */\n    public void flip(int bitIndex) {\n        if (bitIndex < 0)\n            throw new IndexOutOfBoundsException(\"bitIndex < 0: \" + bitIndex);\n\n        int wordIndex = wordIndex(bitIndex);","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-common/src/main/java/org/apache/pulsar/common/util/collections/BitSetRecyclable.java#L323-L359","documentation":"In the same checkRange method, BitSetRecyclable throws IndexOutOfBoundsException(\"toIndex < 0: \" + toIndex) when the upper bound of a bit range is negative, after the fromIndex check. Since fromIndex <= toIndex is enforced later, a negative toIndex almost always means both bounds are negative, but it is checked independently to give a precise message. flip/set/clear/get range variants all funnel through this guard.","triggerScenarios":"Calling set(fromIndex, toIndex), clear(fromIndex, toIndex), flip(fromIndex, toIndex) or get(fromIndex, toIndex) with toIndex < 0 — e.g. toIndex computed as length + delta where delta is negative, or both indices taken from an uninitialized/empty result like (start, end) of an empty span.","commonSituations":"Slicing ranges from deserialized data where the length field was 0 or negative, producing toIndex = start + length < 0; passing (0, list.size() - 1) style bounds when the collection is empty (toIndex = -1); copying range logic between 0-based and 1-based systems.","solutions":["Validate bounds before the call: if (toIndex < 0) return/handle, or normalize empty ranges to (0, 0).","For inclusive-style bounds converted to exclusive (toIndex = end + 1), ensure the conversion handles end = -1 (empty) by skipping the operation entirely.","Check the arithmetic producing toIndex (additions with negative lengths, size()-1 on empty collections).","If bounds come from external data, validate start >= 0 and end >= start against the actual bit-set capacity before calling."],"exampleFix":"// before\nint end = values.size() - 1; // values empty -> end = -1\nbitSet.set(0, end);\n\n// after\nint end = values.size() - 1;\nif (end >= 0) {\n    bitSet.set(0, end);\n}","handlingStrategy":"validation","validationCode":"static void requireValidRange(int fromIndex, int toIndex) {\n    if (fromIndex < 0 || toIndex < 0 || fromIndex > toIndex)\n        throw new IllegalArgumentException(\"invalid range [\" + fromIndex + \", \" + toIndex + \")\");\n}","typeGuard":"static boolean isValidRange(int from, int to) { return from >= 0 && to >= from; }","tryCatchPattern":"try {\n    bitSet.set(from, to);\n} catch (IndexOutOfBoundsException e) {\n    log.warn(\"Skipping invalid bit range [{}, {}): {}\", from, to, e.getMessage());\n    // treat as empty range or escalate to a data-corruption error\n}","preventionTips":["Compute exclusive upper bounds defensively: skip the operation when the range is empty (toIndex <= fromIndex <= 0).","Never derive toIndex as size()-1 for inclusive-style APIs; convert explicitly to exclusive bounds with an empty-case branch.","Validate (start, length) pairs from wire/serialized data before constructing ranges.","Centralize range construction in one helper that runs the same checks as checkRange."],"tags":["java","bitset","index-out-of-bounds"],"backgroundTag":"negative-array-index","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}