LMAX-Exchange/disruptor · error · IllegalArgumentException

bufferSize must be a power of 2

Error message

bufferSize must be a power of 2

What it means

Thrown by the AbstractSequencer constructor when the buffer size is not a power of 2 (Integer.bitCount(bufferSize) != 1). Disruptor uses bitmask arithmetic (sequence & indexMask) instead of modulo to index into the ring buffer, which only works when the capacity is exactly 1, 2, 4, 8, 16, ... entries.

Source

Thrown at src/main/java/com/lmax/disruptor/AbstractSequencer.java:52

    protected final WaitStrategy waitStrategy;
    protected final Sequence cursor = new Sequence(Sequencer.INITIAL_CURSOR_VALUE);
    protected volatile Sequence[] gatingSequences = new Sequence[0];

    /**
     * Create with the specified buffer size and wait strategy.
     *
     * @param bufferSize   The total number of entries, must be a positive power of 2.
     * @param waitStrategy The wait strategy used by this sequencer
     */
    public AbstractSequencer(final int bufferSize, final WaitStrategy waitStrategy)
    {
        if (bufferSize < 1)
        {
            throw new IllegalArgumentException("bufferSize must not be less than 1");
        }
        if (Integer.bitCount(bufferSize) != 1)
        {
            throw new IllegalArgumentException("bufferSize must be a power of 2");
        }

        this.bufferSize = bufferSize;
        this.waitStrategy = waitStrategy;
    }

    /**
     * @see Sequencer#getCursor()
     */
    @Override
    public final long getCursor()
    {
        return cursor.get();
    }

    /**
     * @see Sequencer#getBufferSize()
     */

View on GitHub (pinned to c871ca4982)

Solutions

  1. Change the buffer size to the nearest power of 2 (e.g. 1000 -> 1024, 3000 -> 4096).
  2. If the size is dynamic, round up: int size = Integer.highestOneBit(desired - 1) << 1;
  3. Add a startup assertion/util check so misconfiguration is caught with a clearer message.

Example fix

// before
RingBuffer<Event> rb = RingBuffer.createMultiProducer(Event::new, 1000);

// after
RingBuffer<Event> rb = RingBuffer.createMultiProducer(Event::new, 1024);
Defensive patterns

Strategy: validation

Validate before calling

static int ceilPow2(int desired) {
    return Integer.highestOneBit(Math.max(1, desired - 1)) << 1;
}
// use: ceilPow2(1000) == 1024

Prevention

When it happens

Trigger: Calling new Disruptor<>(factory, 1000, threadFactory) or RingBuffer.createMultiProducer(factory, 1000) — any size whose binary representation has more than one bit set. Also triggered by sizes like 0-adjacent odd values after fixing error 0.

Common situations: Developer picks a 'round decimal' size (100, 1000, 3000) out of habit; size computed dynamically (e.g. throughput target * multiplier) without rounding up to a power of 2; porting code from another queue library that allowed arbitrary capacities.

Related errors


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