LMAX-Exchange/disruptor · error · IllegalArgumentException

n must be > 0

Error message

n must be > 0

What it means

Thrown by MultiProducerSequencer.tryNext(int n) when n < 1. Unlike next(n), tryNext only rejects non-positive claims; claiming more than the buffer is fine here because it fails atomically with InsufficientCapacityException instead of blocking. A zero/negative n would corrupt the claim arithmetic, so it is rejected.

Source

Thrown at src/main/java/com/lmax/disruptor/MultiProducerSequencer.java:156

    /**
     * @see Sequencer#tryNext()
     */
    @Override
    public long tryNext() throws InsufficientCapacityException
    {
        return tryNext(1);
    }

    /**
     * @see Sequencer#tryNext(int)
     */
    @Override
    public long tryNext(final int n) throws InsufficientCapacityException
    {
        if (n < 1)
        {
            throw new IllegalArgumentException("n must be > 0");
        }

        long current;
        long next;

        do
        {
            current = cursor.get();
            next = current + n;

            if (!hasAvailableCapacity(gatingSequences, n, current))
            {
                throw InsufficientCapacityException.INSTANCE;
            }
        }
        while (!cursor.compareAndSet(current, next));

        return next;

View on GitHub (pinned to c871ca4982)

Solutions

  1. Check n >= 1 before calling tryNext; break out of the claiming loop when the computed count reaches 0.
  2. Use the single-slot form ringBuffer.tryNext() (equivalent to tryNext(1)) when claiming one event.
  3. Unit-test the boundary iteration where the remaining count becomes 0.

Example fix

// before
long seq = ringBuffer.tryNext(remaining); // remaining == 0 on last loop pass

// after
if (remaining < 1) break;
long seq = ringBuffer.tryNext(remaining);
Defensive patterns

Strategy: validation

Validate before calling

if (n >= 1) {
    long seq = ringBuffer.tryNext(n);
    // publish
}

Prevention

When it happens

Trigger: Calling ringBuffer.tryNext(0) or tryNext(negativeValue), typically with a dynamically computed batch size such as tryNext(remaining) where remaining hits 0 in a loop.

Common situations: A drain loop that computes 'how many to claim' and hits 0 on its last iteration; consumer-side batching math that underflows; reusing a size variable after it has been decremented to 0.

Related errors


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