{"record":{"id":"882e0ab96e50339f","repo":"apache/pulsar","slug":"value-out-of-range-0-max-uint32-value","errorCode":null,"errorMessage":"Value out of range [0, <MAX_UINT32>]: <value>","messagePattern":"Value out of range \\[0, <MAX_UINT32>\\]: <value>","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-common/src/main/java/org/apache/pulsar/common/util/collections/ConcurrentRoaringBitmap.java","lineNumber":458,"sourceCode":"        } catch (IOException e) {\n            throw new RuntimeException(\"Failed to deserialize LongBitmap\", e);\n        }\n    }\n\n    /**\n     * Trims the underlying bitmap if enough removals have accumulated or it's empty.\n     * Caller must hold the write lock and have already updated {@link #removesSinceTrim}.\n     */\n    private void maybeTrim() {\n        if (removesSinceTrim >= TRIM_AFTER_REMOVES || bitmap.isEmpty()) {\n            bitmap.trim();\n            removesSinceTrim = 0;\n        }\n    }\n\n    private static void validateRange(long value) {\n        if (value < 0 || value > MAX_UINT32) {\n            throw new IllegalArgumentException(\n                    \"Value out of range [0, \" + MAX_UINT32 + \"]: \" + value);\n        }\n    }\n\n    /** Minimal {@link DataInput} over a {@link ByteBuffer} for RoaringBitmap deserialization. */\n    private static final class ByteBufferDataInput implements DataInput {\n        private final ByteBuffer buffer;\n\n        ByteBufferDataInput(ByteBuffer buffer) {\n            this.buffer = buffer;\n        }\n\n        @Override\n        public void readFully(byte[] b) {\n            buffer.get(b);\n        }\n\n        @Override","sourceCodeStart":440,"sourceCodeEnd":476,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-common/src/main/java/org/apache/pulsar/common/util/collections/ConcurrentRoaringBitmap.java#L440-L476","documentation":"ConcurrentRoaringBitmap.validateRange rejects values outside the unsigned 32-bit range [0, 4294967295] because the underlying RoaringBitmap stores ints; negative or >MAX_UINT32 values cannot be represented.","triggerScenarios":"Calling add/remove/checkedAdd with a negative long or a value > 4294967295 (e.g. a full unsigned-64 id, or negative sentinel).","commonSituations":"Storing 64-bit ledger/entry ids directly when the bitmap only fits 32-bit range; values that overflowed int arithmetic into negatives.","solutions":["Use a Set/LongBitmap structure for values above 2^32-1 or negative","Validate input ranges before adding to the bitmap"],"exampleFix":"// before\nbitmap.add(id); // id is a 64-bit long\n// after\nif (id >= 0 && id <= 4294967295L) {\n    bitmap.add((int) id);\n} else {\n    long hi = id >>> 32, lo = id & 0xFFFFFFFFL;\n    bitmapsByHiWord.computeIfAbsent(hi, k -> new ConcurrentRoaringBitmap()).add(lo);\n}","handlingStrategy":"validation","validationCode":"static final long MAX_UINT32 = 4294967295L;\nstatic boolean inBitmapRange(long v) {\n    return v >= 0 && v <= MAX_UINT32;\n}","typeGuard":null,"tryCatchPattern":"try {\n    bitmap.add(value);\n} catch (IllegalArgumentException e) {\n    log.warn(\"Value out of bitmap range: {}\", value);\n}","preventionTips":["Remember the bitmap is 32-bit: split 64-bit ids before storing","Reject negative sentinels before they reach the bitmap","Add range asserts in code that computes values feeding add/remove"],"tags":["java","illegal-argument","range-check"],"backgroundTag":"value-out-of-range","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}