{"id":"0d2cf3831618f1df","repo":"apache/kafka","slug":"reset-not-supported","errorCode":null,"errorMessage":"reset not supported","messagePattern":"reset not supported","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"warning","filePath":"clients/src/main/java/org/apache/kafka/common/compress/Lz4BlockInputStream.java","lineNumber":276,"sourceCode":"\n    @Override\n    public int available() {\n        return decompressedBuffer == null ? 0 : decompressedBuffer.remaining();\n    }\n\n    @Override\n    public void close() {\n        bufferSupplier.release(decompressionBuffer);\n    }\n\n    @Override\n    public void mark(int readlimit) {\n        throw new RuntimeException(\"mark not supported\");\n    }\n\n    @Override\n    public void reset() {\n        throw new RuntimeException(\"reset not supported\");\n    }\n\n    /**\n     * Checks whether the version of lz4 on the classpath has the fix for reading from ByteBuffers with\n     * non-zero array offsets (see https://github.com/lz4/lz4-java/pull/65)\n     */\n    static void detectBrokenLz4Version() {\n        byte[] source = new byte[]{1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3};\n        final LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor();\n\n        final byte[] compressed = new byte[compressor.maxCompressedLength(source.length)];\n        final int compressedLength = compressor.compress(source, 0, source.length, compressed, 0,\n                                                         compressed.length);\n\n        // allocate an array-backed ByteBuffer with non-zero array-offset containing the compressed data\n        // a buggy decompressor will read the data from the beginning of the underlying array instead of\n        // the beginning of the ByteBuffer, failing to decompress the invalid data.\n        final byte[] zeroes = {0, 0, 0, 0, 0};","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/compress/Lz4BlockInputStream.java#L258-L294","documentation":"reset() is overridden in Lz4BlockInputStream to unconditionally throw RuntimeException because the underlying ByteBuffer has already been advanced past the decompressed bytes and there is no stored mark to return to. Pairs with mark(int) (error 312) — the class declares neither operation is supported.","triggerScenarios":"Any invocation of Lz4BlockInputStream.reset(), e.g. from a parser or wrapper that previously called mark() and now attempts to rewind. Reached at line 276. Often thrown right after error 312 if a caller ignores the mark() failure.","commonSituations":"Same shape as error 312: third-party IO/serialization libraries that assume mark/reset; migrating code from a resettable stream; defensive reset() calls in cleanup paths. Indicates the caller violated the documented InputStream contract for this class.","solutions":["Eliminate the reset() call; Lz4BlockInputStream is single-pass.","Buffer the decompressed output into a byte[] or ByteBuffer upstream and replay from there.","Verify the calling library honors markSupported()==false before invoking reset()."],"exampleFix":"// before\nInputStream in = new Lz4BlockInputStream(buf, supplier, true);\nin.mark(0);\nreadHeader(in);\nin.reset();\n\n// after\nByteArrayOutputStream tmp = new ByteArrayOutputStream();\ntry (InputStream in = new Lz4BlockInputStream(buf, supplier, true)) {\n    in.transferTo(tmp);\n}\nbyte[] all = tmp.toByteArray(); // replay as many times as needed","handlingStrategy":"validation","validationCode":"// Symmetric to mark(): reset() is only valid when markSupported() is true.\nInputStream in = ...;\nif (in.markSupported()) {\n    in.reset();\n} else {\n    throw new IllegalStateException(\"Cannot reset non-bufferable LZ4 stream; re-open the source\");\n}","typeGuard":"static boolean canReset(InputStream in) {\n    return in != null && in.markSupported(); // reset capability == mark capability in java.io\n}","tryCatchPattern":"try {\n    in.reset();\n} catch (RuntimeException e) {\n    if (\"reset not supported\".equals(e.getMessage())) {\n        // re-open the LZ4 stream from the original ByteBuffer instead of resetting.\n    } else throw e;\n}","preventionTips":["Treat decompressed Kafka records as a forward-only cursor; do not design parsing that requires rewinding.","If replay is required, materialize the decompressed output once into a byte[] or list and iterate that repeatedly.","Pair every mark() with a guarded reset() — static analysis tools can flag unguarded reset() calls.","Document at the call site that the stream is consumed exactly once."],"tags":["compression","lz4","io","api-misuse","kafka-clients"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}