apache/kafka · warning · RuntimeException

mark not supported

Error message

mark not supported

What it means

mark(int) is overridden in Lz4BlockInputStream to unconditionally throw RuntimeException because the stream consumes and decompresses from a forward-only ByteBuffer and cannot snapshot a rewind point. This is a deliberate API contract: the class does not support mark/reset semantics inherited from java.io.InputStream.

Source

Thrown at clients/src/main/java/org/apache/kafka/common/compress/Lz4BlockInputStream.java:271

        }
        int skipped = (int) Math.min(n, available());
        decompressedBuffer.position(decompressedBuffer.position() + skipped);
        return skipped;
    }

    @Override
    public int available() {
        return decompressedBuffer == null ? 0 : decompressedBuffer.remaining();
    }

    @Override
    public void close() {
        bufferSupplier.release(decompressionBuffer);
    }

    @Override
    public void mark(int readlimit) {
        throw new RuntimeException("mark not supported");
    }

    @Override
    public void reset() {
        throw new RuntimeException("reset not supported");
    }

    /**
     * Checks whether the version of lz4 on the classpath has the fix for reading from ByteBuffers with
     * non-zero array offsets (see https://github.com/lz4/lz4-java/pull/65)
     */
    static void detectBrokenLz4Version() {
        byte[] source = new byte[]{1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3};
        final LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor();

        final byte[] compressed = new byte[compressor.maxCompressedLength(source.length)];
        final int compressedLength = compressor.compress(source, 0, source.length, compressed, 0,
                                                         compressed.length);

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Remove the mark() call — Lz4BlockInputStream is forward-only by design; buffer the decompressed bytes upstream if you need re-read.
  2. If re-read is genuinely required, fully drain the stream into a ByteArrayOutputStream / ByteBuffer first, then replay that buffer.
  3. Guard callers with an explicit markSupported() check (it inherits false from InputStream) before invoking mark().

Example fix

// before
InputStream decompressed = new Lz4BlockInputStream(buf, supplier, true);
decompressed.mark(1024);
...
decompressed.reset();

// after: buffer the whole frame if you need re-read
ByteArrayOutputStream drained = new ByteArrayOutputStream();
try (InputStream in = new Lz4BlockInputStream(buf, supplier, true)) {
    in.transferTo(drained);
}
byte[] replayable = drained.toByteArray();
Defensive patterns

Strategy: validation

Validate before calling

// Lz4BlockInputStream.markSupported() is hardcoded false.
// Guard every call site that reaches for mark().
InputStream in = ...;
if (in.markSupported()) {
    in.mark(readlimit);
} else {
    // buffer externally, or re-open the source
}

Type guard

// Narrow on the capability, not the class — works for any non-markable stream.
static boolean canMark(InputStream in) {
    return in != null && in.markSupported();
}

Try / catch

try {
    in.mark(readlimit);
} catch (RuntimeException e) {
    if ("mark not supported".equals(e.getMessage())) {
        // Fall back to buffered read-into-byte[] and replay from memory.
    } else throw e;
}

Prevention

When it happens

Trigger: Any code calling Lz4BlockInputStream.mark(readLimit) — typically a wrapper utility, a third-party library (e.g. some IOHelpers, Apache Commons IO, certain serialization frameworks), or generated code that probes markSupported() incorrectly and then calls mark(). Triggered at line 271.

Common situations: Using a generic InputStream wrapper that assumes mark/reset (e.g. some XML/JSON parsers, java.io.BufferedInputStream-style helpers) on top of a Kafka LZ4 stream; old code migrated from a different decompressor that did support mark; testing utilities that mark every stream defensively. Less common with direct Kafka consumers, more common in Connect transforms or Streams custom serializers.

Related errors


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/32fdce6c90a8008a.json. Report an issue: GitHub.