netty/netty · error · java.lang.UnsupportedOperationException

direct buffer

Error message

direct buffer

What it means

Thrown by PooledDirectByteBuf.array() because a pooled direct (off-heap) ByteBuf does not back its data with an on-heap byte[]. Netty's contract requires hasArray() to be checked first; array() is only valid when hasArray() returns true. Calling array() on a direct buffer is a programming error, not a transient failure.

Source

Thrown at buffer/src/main/java/io/netty/buffer/PooledDirectByteBuf.java:302

        tmpBuf.put(tmp, 0, readBytes);
        return readBytes;
    }

    @Override
    public ByteBuf copy(int index, int length) {
        checkIndex(index, length);
        ByteBuf copy = alloc().directBuffer(length, maxCapacity());
        return copy.writeBytes(this, index, length);
    }

    @Override
    public boolean hasArray() {
        return false;
    }

    @Override
    public byte[] array() {
        throw new UnsupportedOperationException("direct buffer");
    }

    @Override
    public int arrayOffset() {
        throw new UnsupportedOperationException("direct buffer");
    }

    @Override
    public boolean hasMemoryAddress() {
        PoolChunk<ByteBuffer> chunk = this.chunk;
        return chunk != null && chunk.cleanable.hasMemoryAddress();
    }

    @Override
    public long memoryAddress() {
        ensureAccessible();
        if (!hasMemoryAddress()) {
            throw new UnsupportedOperationException();

View on GitHub (pinned to 70040aacae)

Solutions

  1. Guard with if (buf.hasArray()) before calling buf.array().
  2. Use buf.nioBuffer() / buf.nioBuffers() to obtain a ByteBuffer view instead of array().
  3. Copy to a heap buffer first: ByteBuf heap = buf.copy(); if hasArray() is required downstream.
  4. Configure the allocator/channel to use heap buffers if array() access is mandatory.

Example fix

// before
byte[] data = buf.array();

// after
byte[] data;
if (buf.hasArray()) {
    data = buf.array();
} else {
    data = new byte[buf.readableBytes()];
    buf.getBytes(buf.readerIndex(), data);
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate before calling array()
if (buf.hasArray()) {
    byte[] arr = buf.array();
} else {
    byte[] arr = new byte[buf.readableBytes()];
    buf.getBytes(buf.readerIndex(), arr);
}

Type guard

// Utility guard for any ByteBuf
static byte[] arrayOrCopy(ByteBuf buf) {
    if (buf.hasArray()) {
        return buf.array();
    }
    byte[] copy = new byte[buf.readableBytes()];
    buf.getBytes(buf.readerIndex(), copy);
    return copy;
}

Prevention

When it happens

Trigger: Calling buf.array() on a buffer obtained from PooledByteBufAllocator.DEFAULT.directBuffer(...) or any allocator that returns PooledDirectByteBuf. Also hit when passing a pooled direct buffer to code that unconditionally invokes array() (e.g. some JDK helpers or legacy serializers).

Common situations: Switching an allocator from heap to direct in configuration, or migrating from Unpooled.buffer() (heap) to a pooled direct allocator. Third-party libraries (e.g. older message serializers, Kryo) that assume heap-backed buffers.

Related errors


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