netty/netty · error · IllegalArgumentException

initialCapacity: %d (expected: not greater than maxCapacity(

Error message

initialCapacity: %d (expected: not greater than maxCapacity(%d)

What it means

Thrown by AbstractByteBufAllocator.validate as an IllegalArgumentException when allocating a buffer/composite with initialCapacity greater than maxCapacity. Netty requires the initial allocation to fit within the declared ceiling so a caller cannot accidentally request more than the configured maximum at construction time.

Source

Thrown at buffer/src/main/java/io/netty/buffer/AbstractByteBufAllocator.java:210

    @Override
    public CompositeByteBuf compositeHeapBuffer(int maxNumComponents) {
        return toLeakAwareBuffer(new CompositeByteBuf(this, false, maxNumComponents));
    }

    @Override
    public CompositeByteBuf compositeDirectBuffer() {
        return compositeDirectBuffer(DEFAULT_MAX_COMPONENTS);
    }

    @Override
    public CompositeByteBuf compositeDirectBuffer(int maxNumComponents) {
        return toLeakAwareBuffer(new CompositeByteBuf(this, true, maxNumComponents));
    }

    private static void validate(int initialCapacity, int maxCapacity) {
        checkPositiveOrZero(initialCapacity, "initialCapacity");
        if (initialCapacity > maxCapacity) {
            throw new IllegalArgumentException(String.format(
                    "initialCapacity: %d (expected: not greater than maxCapacity(%d)",
                    initialCapacity, maxCapacity));
        }
    }

    /**
     * Create a heap {@link ByteBuf} with the given initialCapacity and maxCapacity.
     */
    protected abstract ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity);

    /**
     * Create a direct {@link ByteBuf} with the given initialCapacity and maxCapacity.
     */
    protected abstract ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity);

    @Override
    public String toString() {
        return StringUtil.simpleClassName(this) + "(directByDefault: " + directByDefault + ')';

View on GitHub (pinned to 70040aacae)

Solutions

  1. Ensure initialCapacity <= maxCapacity in every alloc.* call; derive both from a single validated config.
  2. If maxCapacity should equal initialCapacity, pass the same value or omit max (defaults to Integer.MAX_VALUE).
  3. Add a startup assertion: checkArgument(initialCapacity <= maxCapacity) before bootstrapping.

Example fix

// before
ByteBuf b = alloc.buffer(8192, 4096); // 8192 > 4096

// after
ByteBuf b = alloc.buffer(4096, 8192); // initial <= max
Defensive patterns

Strategy: validation

Validate before calling

// Validate allocator args before construction
if (initialCapacity > maxCapacity) {
    throw new IllegalArgumentException("initialCapacity > maxCapacity");
}
ByteBuf b = alloc.buffer(initialCapacity, maxCapacity);

Type guard

static boolean validAllocArgs(int initial, int max) {
    return initial >= 0 && max >= 0 && initial <= max;
}

Prevention

When it happens

Trigger: Calling alloc.buffer(initial, max) or alloc.heapBuffer/directBuffer/compositeBuffer with initialCapacity > maxCapacity; computing both from config where they were set inconsistently.

Common situations: Misconfigured bootstrap/allocator options where initial and max pool sizes were edited independently; copy-pasting allocation calls and bumping only one of the two numbers.

Related errors


AI-assisted analysis of netty/netty@70040aacae (2026-08-14). Data as JSON: /api/errors/d07594704f0805a3. Report an issue: GitHub.