{"record":{"id":"b424f38dc18a9998","repo":"quarkusio/quarkus","slug":"buffer-hasn-t-backing-byte-array","errorCode":null,"errorMessage":"buffer hasn't backing byte array","messagePattern":"buffer hasn't backing byte array","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/QuarkusHttpPostBodyUtil.java","lineNumber":99,"sourceCode":"\n    /**\n     * This class intends to decrease the CPU in seeking ahead some bytes in\n     * HttpPostRequestDecoder\n     */\n    static class SeekAheadOptimize {\n        byte[] bytes;\n        int readerIndex;\n        int pos;\n        int origPos;\n        int limit;\n        ByteBuf buffer;\n\n        /**\n         * @param buffer buffer with a backing byte array\n         */\n        SeekAheadOptimize(ByteBuf buffer) {\n            if (!buffer.hasArray()) {\n                throw new IllegalArgumentException(\"buffer hasn't backing byte array\");\n            }\n            this.buffer = buffer;\n            bytes = buffer.array();\n            readerIndex = buffer.readerIndex();\n            origPos = pos = buffer.arrayOffset() + readerIndex;\n            limit = buffer.arrayOffset() + buffer.writerIndex();\n        }\n\n        /**\n         *\n         * @param minus this value will be used as (currentPos - minus) to set\n         *        the current readerIndex in the buffer.\n         */\n        void setReadPosition(int minus) {\n            pos -= minus;\n            readerIndex = getReadPosition(pos);\n            buffer.readerIndex(readerIndex);\n        }","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/multipart/QuarkusHttpPostBodyUtil.java#L81-L117","documentation":"QuarkusHttpPostBodyUtil.SeekAheadOptimize is a fast-path optimization that requires the ByteBuf to have a backing JVM byte array. If buffer.hasArray() is false (e.g. direct or composite buffers), it throws IllegalArgumentException.","triggerScenarios":"Constructing SeekAheadOptimize with a direct (off-heap) ByteBuf or a composite/unpooled buffer without a backing array.","commonSituations":"Netty allocating direct buffers (default with io.netty.maxDirectMemory enabled) for multipart bodies; pooling configurations changed by flags or Netty version upgrades.","solutions":["Use the fallback seek-ahead-disabled parsing path (parsing directly on the ByteBuf) when the buffer has no array","Force heap-buffer allocation for multipart request bodies (e.g. -Dio.netty.maxDirectMemory=0)","Copy the buffer into a heap buffer (Unpooled.copiedBuffer / alloc.ioBuffer) before constructing SeekAheadOptimize"],"exampleFix":"// before\nSeekAheadOptimize sao = new SeekAheadOptimize(buffer);\n// after\nSeekAheadOptimize sao = buffer.hasArray() ? new SeekAheadOptimize(buffer) : null; // fall back to non-optimized path","handlingStrategy":"validation","validationCode":"if (!buffer.hasArray()) { /* use the non-optimized parsing path */ }","typeGuard":"null","tryCatchPattern":"try { sao = new SeekAheadOptimize(buffer); } catch (IllegalArgumentException e) { sao = null; /* seek-ahead disabled */ }","preventionTips":["Check buffer.hasArray() before heap-optimizing paths","Run with -Dio.netty.maxDirectMemory=0 if heap buffers are required","Be aware direct/composite buffers depend on Netty allocation settings and versions"],"tags":["netty","bytebuf","multipart","buffer-allocation"],"backgroundTag":"unsupported-operation","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}