apache/kafka · error · IllegalArgumentException
requested size {sizeBytes}<=0
Error message
requested size {sizeBytes}<=0 What it means
Thrown by SimpleMemoryPool.tryAllocate(int sizeBytes) when the requested allocation size is less than 1. The pool refuses zero- or negative-length buffers because they would corrupt the available-memory accounting (the AtomicLong is decremented by sizeBytes on success). It is an IllegalArgumentException raised before any CAS on the pool counter.
Source
Thrown at clients/src/main/java/org/apache/kafka/common/memory/SimpleMemoryPool.java:57
protected final int maxSingleAllocationSize;
protected final AtomicLong startOfNoMemPeriod = new AtomicLong(); //nanoseconds
protected volatile Sensor oomTimeSensor;
public SimpleMemoryPool(long sizeInBytes, int maxSingleAllocationBytes, boolean strict, Sensor oomPeriodSensor) {
if (sizeInBytes <= 0 || maxSingleAllocationBytes <= 0 || maxSingleAllocationBytes > sizeInBytes)
throw new IllegalArgumentException("must provide a positive size and max single allocation size smaller than size."
+ "provided " + sizeInBytes + " and " + maxSingleAllocationBytes + " respectively");
this.sizeBytes = sizeInBytes;
this.strict = strict;
this.availableMemory = new AtomicLong(sizeInBytes);
this.maxSingleAllocationSize = maxSingleAllocationBytes;
this.oomTimeSensor = oomPeriodSensor;
}
@Override
public ByteBuffer tryAllocate(int sizeBytes) {
if (sizeBytes < 1)
throw new IllegalArgumentException("requested size " + sizeBytes + "<=0");
if (sizeBytes > maxSingleAllocationSize)
throw new IllegalArgumentException("requested size " + sizeBytes + " is larger than maxSingleAllocationSize " + maxSingleAllocationSize);
long available;
boolean success = false;
//in strict mode we will only allocate memory if we have at least the size required.
//in non-strict mode we will allocate memory if we have _any_ memory available (so available memory
//can dip into the negative and max allocated memory would be sizeBytes + maxSingleAllocationSize)
long threshold = strict ? sizeBytes : 1;
while ((available = availableMemory.get()) >= threshold) {
success = availableMemory.compareAndSet(available, available - sizeBytes);
if (success)
break;
}
if (success) {
maybeRecordEndOfDrySpell();
} else {View on GitHub (pinned to c31c9215e1)
Solutions
- Inspect the sizeBytes value in the message — if it is 0 or negative, find the caller that computed it and fix the sizing logic.
- Guard the call site: if a payload can legitimately be empty, short-circuit before tryAllocate rather than allocating a zero-length buffer.
- Audit the size computation (e.g. Records.LOG_OVERHEAD, record-batch header, compression overhead) for underflow when individual components are zero.
- Reproduce with producer logging at TRACE to capture the request that produced the bad size; look for record/compression-size calculation around the call.
- If you maintain a custom MemoryPool, ensure tryAllocate callers never pass sizes derived from unchecked user input.
Example fix
// before — computed size can go to zero/negative
int size = payload.length - HEADER_SIZE;
ByteBuffer buf = pool.tryAllocate(size); // throws if payload smaller than HEADER_SIZE
// after — validate before allocating
int size = Math.max(payload.length - HEADER_SIZE, 1);
if (payload.length < HEADER_SIZE) {
throw new IllegalArgumentException("payload " + payload.length + " smaller than header " + HEADER_SIZE);
}
ByteBuffer buf = pool.tryAllocate(size); Defensive patterns
Strategy: validation
Validate before calling
// Guard tryAllocate against non-positive sizes before calling.
int sizeBytes = ...;
if (sizeBytes < 1) {
throw new IllegalArgumentException("Cannot allocate " + sizeBytes + " bytes; size must be >= 1");
}
ByteBuffer buf = pool.tryAllocate(sizeBytes); Type guard
// Treat only positive ints as valid allocation requests.
static boolean isAllocatableSize(int sizeBytes) {
return sizeBytes > 0;
} Try / catch
try {
buf = pool.tryAllocate(sizeBytes);
} catch (IllegalArgumentException e) {
// caller passed garbage — drop the request, do not retry with the same size.
log.warn("Rejected allocation of {} bytes", sizeBytes);
buf = null;
} Prevention
- Coerce message sizes through a serializer/partitioner that guarantees a positive length before pooling.
- Reject zero-length payloads at the application boundary rather than relying on the pool to complain.
- If computing size from a serialized payload, sanity-check the result (>0, not Integer.MAX_VALUE) before allocating.
- Never call tryAllocate with a value derived from an untrusted int without first bounding it.
When it happens
Trigger: Calling tryAllocate(n) where n <= 0 — most often reached transitively when a record batch, send buffer, or request size is computed as zero or negative and handed to the memory pool. In the producer path this can occur when a Serializers/CompressionType produces an empty payload or when a caller computes a size as (a - b) that goes negative under load.
Common situations: A record with an empty value and an empty key combined with a compressor that writes a zero-byte payload; an arithmetic underflow producing a negative size (e.g. size = total - overhead where overhead > total); test code that pre-sizes a buffer from an uninitialized int default of 0; a custom protocol layer that calls tryAllocate(0) as a 'no-op' placeholder; an off-by-one when subtracting record-batch overhead.
Related errors
- Topic name is invalid: {reasonInvalid}
- must provide a positive size and max single allocation size
- Invalid configuration value for 'acks': {acksString}
- Topic cannot be null.
- Invalid timestamp: %d. Timestamp should always be non-negati
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/9131db60b747d74a.json.
Report an issue: GitHub.