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
- Change the buffer size to the nearest power of 2 (e.g. 1000 -> 1024, 3000 -> 4096).
- If the size is dynamic, round up: int size = Integer.highestOneBit(desired - 1) << 1;
- 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
- Default to well-known powers of 2 (1024, 4096, 16384) in config templates.
- When sizes are dynamic, always round up to the next power of 2 at the boundary.
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
- bufferSize must not be less than 1
- value must be a positive number
- maxBatchSize must be greater than 0
- n must be > 0 and < bufferSize
- Thread is already running
AI-assisted analysis of LMAX-Exchange/disruptor@c871ca4982 (2026-08-14).
Data as JSON: /api/errors/33d464e24fe55bc1.
Report an issue: GitHub.