{"record":{"id":"a4ad639e14e7df18","repo":"LMAX-Exchange/disruptor","slug":"both-batchstartsat-and-batchsize-must-be-positive","errorCode":null,"errorMessage":"Both batchStartsAt and batchSize must be positive but got: batchStartsAt {} and batchSize {}","messagePattern":"Both batchStartsAt and batchSize must be positive but got: batchStartsAt (.+?) and batchSize (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/com/lmax/disruptor/RingBuffer.java","lineNumber":904,"sourceCode":"     * @return The number of slots remaining.\n     */\n    @Override\n    public long remainingCapacity()\n    {\n        return sequencer.remainingCapacity();\n    }\n\n    private void checkBounds(final EventTranslator<E>[] translators, final int batchStartsAt, final int batchSize)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(translators, batchStartsAt, batchSize);\n    }\n\n    private void checkBatchSizing(final int batchStartsAt, final int batchSize)\n    {\n        if (batchStartsAt < 0 || batchSize < 0)\n        {\n            throw new IllegalArgumentException(\"Both batchStartsAt and batchSize must be positive but got: batchStartsAt \" + batchStartsAt + \" and batchSize \" + batchSize);\n        }\n        else if (batchSize > bufferSize)\n        {\n            throw new IllegalArgumentException(\"The ring buffer cannot accommodate \" + batchSize + \" it only has space for \" + bufferSize + \" entities.\");\n        }\n    }\n\n    private <A> void checkBounds(final A[] arg0, final int batchStartsAt, final int batchSize)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(arg0, batchStartsAt, batchSize);\n    }\n\n    private <A, B> void checkBounds(final A[] arg0, final B[] arg1, final int batchStartsAt, final int batchSize)\n    {\n        checkBatchSizing(batchStartsAt, batchSize);\n        batchOverRuns(arg0, batchStartsAt, batchSize);\n        batchOverRuns(arg1, batchStartsAt, batchSize);","sourceCodeStart":886,"sourceCodeEnd":922,"githubUrl":"https://github.com/LMAX-Exchange/disruptor/blob/c871ca49826a6be7ada6957f6fbafcfecf7b1f87/src/main/java/com/lmax/disruptor/RingBuffer.java#L886-L922","documentation":"Thrown by RingBuffer.checkBatchSizing during batch-publish overloads (publishEvents, tryPublishEvents) when batchStartsAt is negative or batchSize is negative. batchStartsAt is the offset into your argument arrays where the batch begins; both it and the count must be non-negative for the copy into the ring to be well-defined.","triggerScenarios":"Calling ringBuffer.publishEvents(translators, -1, 2) or publishEvents(translators, 0, -2) — i.e. passing a negative offset or count into any batch publish variant (translators, one-arg, two-arg, three-arg, varargs forms).","commonSituations":"Offset arithmetic bugs (batchStartsAt = lastEnd - batchLength going negative at a boundary); loop code computing 'start = i - batchSize' incorrectly; passing a sentinel like -1 to mean 'from the start'.","solutions":["Fix the offset/count math: batchStartsAt must be >= 0 and batchSize >= 1.","To publish from the beginning of the array, pass 0 explicitly rather than -1.","Log batchStartsAt/batchSize before publishing while debugging boundary loops."],"exampleFix":"// before\nringBuffer.publishEvents(translators, offset - translators.length, count); // negative offset\n\n// after\nint start = Math.max(0, offset);\nringBuffer.publishEvents(translators, start, count);","handlingStrategy":"validation","validationCode":"if (batchStartsAt < 0 || batchSize < 1 || batchStartsAt >= translators.length) {\n    throw new IllegalArgumentException(\"bad batch bounds: start=\" + batchStartsAt + \" size=\" + batchSize);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use 0 as the explicit start offset; never pass sentinels like -1.","Compute offsets in one place and unit-test boundary values."],"tags":["disruptor","ring-buffer","batching","publish","validation"],"backgroundTag":null,"analyzedSha":"c871ca49826a6be7ada6957f6fbafcfecf7b1f87","analyzedAt":"2026-08-14T14:22:36.358Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}