elastic/elasticsearch · error · LZ4Exception

Too large literalLen

Error message

Too large literalLen

What it means

When the literal-length nibble equals RUN_MASK (15), the decoder reads a chain of 0xFF extension bytes, adding 255 each time. If the accumulated literalLen overflows int (goes negative), the declared literal length exceeds any plausible buffer and the stream is malformed. This bounds the variable-length literal encoding.

Source

Thrown at libs/lz4/src/main/java/org/elasticsearch/lz4/ESLZ4Decompressor.java:88

        int sOff = srcOff;
        int dOff = destOff;

        while (true) {
            if (sOff >= srcEnd) {
                throw new LZ4Exception("Malformed input at " + sOff);
            }
            final int token = SafeUtils.readByte(src, sOff) & 0xFF;
            ++sOff;

            // literals
            int literalLen = token >>> ML_BITS;
            if (literalLen == RUN_MASK) {
                byte len = (byte) 0xFF;
                while (sOff < srcEnd && (len = SafeUtils.readByte(src, sOff++)) == (byte) 0xFF) {
                    literalLen += 0xFF;
                    if (literalLen < 0) {
                        throw new LZ4Exception("Too large literalLen");
                    }
                }
                literalLen += len & 0xFF;
            }

            final int literalCopyEnd = dOff + literalLen;
            // Check for overflow
            if (literalCopyEnd < dOff) {
                throw new LZ4Exception("Too large literalLen");
            }

            if (notEnoughSpace(destEnd - literalCopyEnd, COPY_LENGTH) || notEnoughSpace(srcEnd - sOff, COPY_LENGTH + literalLen)) {

                if (literalCopyEnd != destEnd) {
                    throw new LZ4Exception("Malformed input at " + sOff);
                } else if (notEnoughSpace(srcEnd - sOff, literalLen)) {
                    throw new LZ4Exception("Malformed input at " + sOff);

View on GitHub (pinned to db6a809a66)

Solutions

  1. Treat the input as corrupt; do not trust the source block.
  2. Restore the data from a known-good replica or snapshot.
  3. If generating the input programmatically, ensure the literal-length encoding matches the LZ4 spec.
Defensive patterns

Strategy: try-catch

Validate before calling

// No safe pre-check; overflow is detected during decode. Bound the declared destLen against srcLen as a heuristic.
if (destLen > srcLen * 255L) { // literals can't expand more than ~255x
    throw new IllegalArgumentException("Implausible LZ4 destLen for given srcLen");
}

Try / catch

try {
    ESLZ4Decompressor.INSTANCE.decompress(src, srcOff, dest, destOff, destLen);
} catch (LZ4Exception e) {
    // literal-length overflow => corrupt or adversarial input
    markCorruptAndRecover();
}

Prevention

When it happens

Trigger: Decompressing an LZ4 block whose literal-length extension bytes sum beyond Integer.MAX_VALUE, i.e. more than ~8.4 million 0xFF bytes precede the terminating length byte. Indicates crafted or severely corrupt input.

Common situations: Fuzzed or adversarial LZ4 input. Memory corruption that overwrites length bytes with 0xFF. A buffer from an incompatible LZ4 implementation.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/230232e1c840b98b. Report an issue: GitHub.