apache/incubator-seata · error · IllegalArgumentException
Failed to decompress zstd data
Error message
Failed to decompress zstd data
What it means
Wrapped IOException from ZstdUtil.decompress thrown as IllegalArgumentException('Failed to decompress zstd data', e). ZstdInputStream fails when the payload lacks the zstd frame magic (0x28 0xB5 0x2F 0xFD), is truncated, or fails checksum validation. Note this class throws IllegalArgumentException, not RuntimeException, unlike the gzip/zip utils.
Source
Thrown at compressor/seata-compressor-zstd/src/main/java/org/apache/seata/compressor/zstd/ZstdUtil.java:54
return Zstd.compress(bytes);
}
public static byte[] decompress(byte[] bytes) {
if (bytes == null) {
throw new NullPointerException("bytes is null");
}
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ZstdInputStream zis = new ZstdInputStream(bais);
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[8192];
int len;
while ((len = zis.read(buffer)) > 0) {
baos.write(buffer, 0, len);
}
return baos.toByteArray();
} catch (IOException e) {
throw new IllegalArgumentException("Failed to decompress zstd data", e);
}
}
}
View on GitHub (pinned to e01f97c6db)
Solutions
- Inspect the cause for zstd frame errors ('Unknown frame descriptor' = wrong format, short reads = truncation).
- Align compressor type on all seata participants.
- Regenerate corrupted persisted data; do not retry the same bytes.
- Preflight check for the zstd magic bytes before decompressing untrusted payloads.
Example fix
// before
byte[] out = ZstdUtil.decompress(bytes);
// after
if (bytes.length < 4 || (bytes[0] & 0xff) != 0x28 || (bytes[1] & 0xff) != 0xB5) {
throw new IllegalArgumentException("payload is not zstd framed");
}
byte[] out = ZstdUtil.decompress(bytes); Defensive patterns
Strategy: try-catch
Validate before calling
boolean isZstd(byte[] b) {
return b != null && b.length >= 4
&& (b[0] & 0xff) == 0x28 && (b[1] & 0xff) == 0xB5
&& (b[2] & 0xff) == 0x2F && (b[3] & 0xff) == 0xFD;
} Try / catch
try {
byte[] out = ZstdUtil.decompress(bytes);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().contains("Failed to decompress zstd data")) {
// wrong codec or truncated zstd frame; inspect e.getCause(); reject, don't retry
} else { throw e; }
} Prevention
- After upgrading seata versions, re-verify the default compressor on every participant
- Check the zstd frame magic before decompressing externally stored blobs
- Store compressed blobs in binary-safe (BLOB/BYTEA) columns only
When it happens
Trigger: Feeding non-zstd bytes (gzip/zip/lz4 output) to ZstdUtil.decompress; truncated arrays; corrupted stored payloads; passing an empty non-null array which makes ZstdInputStream throw on the first read.
Common situations: Compressor type mismatch between seata client and server; damaged binary columns in undo/branch tables; proxies altering bodies; upgrading seata where the default compressor changed to zstd while one side still sends uncompressed or differently-compressed data.
Related errors
AI-assisted analysis of apache/incubator-seata@e01f97c6db (2026-08-14).
Data as JSON: /api/errors/5ca8bad90b1c6ebb.
Report an issue: GitHub.