prestodb/presto · error · MalformedInputException

Zstd JNI decompressor failed with

Error message

Zstd JNI decompressor failed with 

What it means

ZstdJniDecompressor delegates to the Zstd JNI library; if Zstd reports an error code for the input bytes, a MalformedInputException is thrown embedding the JNI error name. The compressed block data did not decode as valid Zstandard.

Source

Thrown at presto-orc/src/main/java/com/facebook/presto/orc/zstd/ZstdJniDecompressor.java:35

import io.airlift.compress.Decompressor;
import io.airlift.compress.MalformedInputException;

import java.nio.Buffer;
import java.nio.ByteBuffer;

import static java.lang.StrictMath.toIntExact;

public class ZstdJniDecompressor
        implements Decompressor
{
    @Override
    public int decompress(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int maxOutputLength)
            throws MalformedInputException
    {
        long size = Zstd.decompressByteArray(output, 0, maxOutputLength, input, inputOffset, inputLength);
        if (Zstd.isError(size)) {
            String errorName = Zstd.getErrorName(size);
            throw new MalformedInputException(inputOffset, "Zstd JNI decompressor failed with " + errorName);
        }
        return toIntExact(size);
    }

    @Override
    public void decompress(ByteBuffer input, ByteBuffer output)
            throws MalformedInputException
    {
        if (input.isDirect() || output.isDirect() || !input.hasArray() || !output.hasArray()) {
            throw new IllegalArgumentException("Non-direct byte buffer backed by byte array required");
        }
        int inputOffset = input.arrayOffset() + input.position();
        int outputOffset = output.arrayOffset() + output.position();

        int written = decompress(input.array(), inputOffset, input.remaining(), output.array(), outputOffset, output.remaining());
        ((Buffer) output).position(output.position() + written);
    }
}

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Verify the ORC file's compression kind metadata matches ZSTD.
  2. Scan the file with orc-tools to find the corrupt block.
  3. Update the zstd-jni native library to a compatible version.
  4. Re-transfer/repair the corrupted file.

Example fix

// before
compressor = new ZstdJniDecompressor();
// after: confirm codec from file metadata first
if (metadata.getCompressionKind() != CompressionKind.ZSTD) {
    compressor = Decompressor.forKind(metadata.getCompressionKind());
} else {
    compressor = new ZstdJniDecompressor();
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (metadata.getCompressionKind() != CompressionKind.ZSTD) {
    throw new IOException("codec mismatch, not zstd: " + metadata.getCompressionKind());
}

Try / catch

try { return zstdDecompressor.decompress(in, off, len, out, oOff, max); } catch (MalformedInputException e) {
    throw new DataCorruptionException("zstd decode failed: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: decompress called on bytes that are not valid Zstd (corruption, wrong block offset, or codec mismatch — e.g., file compressed with snappy but read as zstd).

Common situations: ORC file compression kind misread/mismatched; corrupted block boundaries; truncated zstd frame; incompatible zstd-jni version vs. writer's dictionary/frame features.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/ae6a1a351f721438. Report an issue: GitHub.