alibaba/canal · error · IllegalArgumentException

bufferSize must be a power of 2

Error message

bufferSize must be a power of 2

What it means

Thrown as IllegalArgumentException by EventTransactionBuffer.start because the ring buffer implementation uses an index mask (bufferSize - 1) for O(1) slot addressing, which only works when bufferSize is a power of two. Integer.bitCount(bufferSize) != 1 is the power-of-two check; any other size breaks the masking logic.

Source

Thrown at parse/src/main/java/com/alibaba/otter/canal/parse/inbound/EventTransactionBuffer.java:43

    private CanalEntry.Entry[]       entries;

    private AtomicLong               putSequence   = new AtomicLong(INIT_SQEUENCE); // 代表当前put操作最后一次写操作发生的位置
    private AtomicLong               flushSequence = new AtomicLong(INIT_SQEUENCE); // 代表满足flush条件后最后一次数据flush的时间

    private TransactionFlushCallback flushCallback;

    public EventTransactionBuffer(){

    }

    public EventTransactionBuffer(TransactionFlushCallback flushCallback){
        this.flushCallback = flushCallback;
    }

    public void start() throws CanalStoreException {
        super.start();
        if (Integer.bitCount(bufferSize) != 1) {
            throw new IllegalArgumentException("bufferSize must be a power of 2");
        }

        Assert.notNull(flushCallback, "flush callback is null!");
        indexMask = bufferSize - 1;
        entries = new CanalEntry.Entry[bufferSize];
    }

    public void stop() throws CanalStoreException {
        putSequence.set(INIT_SQEUENCE);
        flushSequence.set(INIT_SQEUENCE);

        entries = null;
        super.stop();
    }

    public void add(List<CanalEntry.Entry> entrys) throws InterruptedException {
        for (CanalEntry.Entry entry : entrys) {
            add(entry);

View on GitHub (pinned to 87be50e876)

Solutions

  1. Set canal.instance.transaction.buffer.size to a power of two (e.g. 1024, 2048, 4096, 8192).
  2. If unsure, remove the override to use the default power-of-two value.
  3. When sizing, round up to the next power of two rather than a round decimal.

Example fix

# before
canal.instance.transaction.buffer.size = 2000

# after
canal.instance.transaction.buffer.size = 2048
Defensive patterns

Strategy: validation

Validate before calling

static int nextPow2(int n) { return n <= 0 ? 1 : Integer.highestOneBit((n - 1) << 1 | 1); }
int safe = (Integer.bitCount(bufferSize) == 1) ? bufferSize : nextPow2(bufferSize);
buffer.setBufferSize(safe);

Type guard

boolean isPow2(int n) { return n > 0 && (n & (n - 1)) == 0; }

Prevention

When it happens

Trigger: EventTransactionBuffer.start() runs when the parser starts the transaction buffer. If canal.instance.transaction.buffer.size (the bufferSize) is not 1, 2, 4, 8, ... the check fails. The mask indexMask = bufferSize - 1 and CanalEntry.Entry[bufferSize] array rely on the power-of-two invariant.

Common situations: A user sets canal.instance.transaction.buffer.size to a non-power-of-two value like 1000, 2048 is fine but 2000 is not, or leaves a custom value from tuning. Default is typically a power of two; overriding it incorrectly triggers this at startup.

Related errors


AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14). Data as JSON: /api/errors/0496fb07eee3c72e. Report an issue: GitHub.