LMAX-Exchange/disruptor · error · IllegalArgumentException

A batchSize of: {} with batchStatsAt of: {} will overrun the

Error message

A batchSize of: {} with batchStatsAt of: {} will overrun the available number of arguments: {}

What it means

Thrown by RingBuffer.batchOverRuns during batch publishing when batchStartsAt + batchSize walks past the end of the supplied argument array. The message reports how many arguments actually remain from batchStartsAt; publishing would otherwise read beyond the array and copy garbage (or throw ArrayIndexOutOfBoundsException deep inside the ring).

Source

Thrown at src/main/java/com/lmax/disruptor/RingBuffer.java:944

        final A[] arg0, final B[] arg1, final C[] arg2, final int batchStartsAt, final int batchSize)
    {
        checkBatchSizing(batchStartsAt, batchSize);
        batchOverRuns(arg0, batchStartsAt, batchSize);
        batchOverRuns(arg1, batchStartsAt, batchSize);
        batchOverRuns(arg2, batchStartsAt, batchSize);
    }

    private void checkBounds(final int batchStartsAt, final int batchSize, final Object[][] args)
    {
        checkBatchSizing(batchStartsAt, batchSize);
        batchOverRuns(args, batchStartsAt, batchSize);
    }

    private <A> void batchOverRuns(final A[] arg0, final int batchStartsAt, final int batchSize)
    {
        if (batchStartsAt + batchSize > arg0.length)
        {
            throw new IllegalArgumentException(
                "A batchSize of: " + batchSize +
                    " with batchStatsAt of: " + batchStartsAt +
                    " will overrun the available number of arguments: " + (arg0.length - batchStartsAt));
        }
    }

    private void translateAndPublish(final EventTranslator<E> translator, final long sequence)
    {
        try
        {
            translator.translateTo(get(sequence), sequence);
        }
        finally
        {
            sequencer.publish(sequence);
        }
    }

View on GitHub (pinned to c871ca4982)

Solutions

  1. Clamp the count to the remaining elements: n = Math.min(chunk, args.length - start).
  2. Double-check that batchStartsAt is an index into the SAME array being published.
  3. Write a boundary unit test for the final partial chunk.

Example fix

// before
int count = batchSize; // last chunk overruns the array
ringBuffer.publishEvents(translators, start, count);

// after
int count = Math.min(batchSize, translators.length - start);
ringBuffer.publishEvents(translators, start, count);
Defensive patterns

Strategy: validation

Validate before calling

int count = Math.min(batchSize, args.length - batchStartsAt);
if (batchStartsAt + count > args.length) throw new IllegalArgumentException("batch overruns args");

Prevention

When it happens

Trigger: Calling publishEvents(translators, 8, 4) when translators.length == 10 (8 + 4 = 12 > 10); any variant (tryPublishEvents, publishEvents with arg arrays, varargs) where offset plus count exceeds the source array length.

Common situations: Chunking loop with an incorrect tail calculation (forgetting Math.min for the last chunk); reusing an offset from a previous larger batch; off-by-one where count includes an element outside the array.

Related errors


AI-assisted analysis of LMAX-Exchange/disruptor@c871ca4982 (2026-08-14). Data as JSON: /api/errors/dbaf6be3f7a2fdf4. Report an issue: GitHub.