apache/kafka · error · IllegalArgumentException

provided null buffer

Error message

provided null buffer

What it means

Thrown by SimpleMemoryPool.release(ByteBuffer) when null is passed in. Returning a null buffer breaks the pool's bookkeeping because release() reads previouslyAllocated.capacity() to credit memory back to the AtomicLong; a null buffer would NPE there. The guard rejects null early with a clear IllegalArgumentException instead.

Source

Thrown at clients/src/main/java/org/apache/kafka/common/memory/SimpleMemoryPool.java:91

        if (success) {
            maybeRecordEndOfDrySpell();
        } else {
            if (oomTimeSensor != null) {
                startOfNoMemPeriod.compareAndSet(0, System.nanoTime());
            }
            log.trace("refused to allocate buffer of size {}", sizeBytes);
            return null;
        }

        ByteBuffer allocated = ByteBuffer.allocate(sizeBytes);
        bufferToBeReturned(allocated);
        return allocated;
    }

    @Override
    public void release(ByteBuffer previouslyAllocated) {
        if (previouslyAllocated == null)
            throw new IllegalArgumentException("provided null buffer");

        bufferToBeReleased(previouslyAllocated);
        availableMemory.addAndGet(previouslyAllocated.capacity());
        maybeRecordEndOfDrySpell();
    }

    @Override
    public long size() {
        return sizeBytes;
    }

    @Override
    public long availableMemory() {
        return availableMemory.get();
    }

    @Override
    public boolean isOutOfMemory() {

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Check the message — it almost always means tryAllocate returned null (pool exhausted) and the finally block blindly called release(null).
  2. Guard the release: `if (buf != null) pool.release(buf);` so exhausted-pool paths don't try to return a null buffer.
  3. If the release site is in your own code, audit every allocation point and pair it with a conditional release in finally.
  4. If you are seeing this from inside the Kafka producer itself, file a bug — internal call sites already guard against null; this indicates a version-specific regression.
  5. Add a unit test that exercises the pool-exhausted path (allocate until tryAllocate returns null, then trigger the cleanup hook) to confirm the fix.

Example fix

// before — finally releases unconditionally
ByteBuffer buf = pool.tryAllocate(size);
try {
    write(buf);
} finally {
    pool.release(buf);  // throws if tryAllocate returned null when pool was empty
}

// after — release only when allocation actually succeeded
ByteBuffer buf = pool.tryAllocate(size);
if (buf == null) throw new BufferExhaustedException("pool exhausted for size " + size);
try {
    write(buf);
} finally {
    pool.release(buf);
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Only release buffers you actually got from tryAllocate.
ByteBuffer buf = ...;
if (buf == null) {
    // skip silently — releasing null is a programming error in the pool's contract.
    return;
}
pool.release(buf);

Type guard

// Track 'buffer came from the pool' as a non-null type so null releases are impossible.
static void releaseIfPresent(MemoryPool pool, ByteBuffer buf) {
    if (buf != null) pool.release(buf);
}

Try / catch

try {
    pool.release(buf);
} catch (IllegalArgumentException e) {
    // a null release is a coding bug — log loudly and audit the release path.
    log.error("Attempted to release a null buffer to the pool", e);
}

Prevention

When it happens

Trigger: A caller hands a previously-allocated buffer back to the pool but the local reference is null — e.g. a try/finally that releases the buffer even though tryAllocate returned null (the pool returns null when exhausted in non-blocking mode), or a code path that nulls out the reference after use and then calls release in a finally block.

Common situations: Finally block that unconditionally calls pool.release(buf) where buf was assigned from a tryAllocate that legitimately returned null under backpressure; a producer/sender code path that clears its buffer reference on send-completion but the cleanup hook still runs; refactoring that introduced an early `buf = null;` before release; test code reusing a null buffer mock.

Related errors


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/98ba4e2c345389cd.json. Report an issue: GitHub.