apache/incubator-seata · error · RuntimeException

BZip2 decompress error

Error message

BZip2 decompress error

What it means

BZip2Util.decompress wraps IOException from CBZip2InputStream in RuntimeException('BZip2 decompress error'). commons-compress throws IOException for invalid stream headers, truncated data, or CRC mismatches, so this exception in Seata almost always means the bytes given are not a complete/valid bzip2 stream — commonly because they were compressed by a different algorithm or corrupted in transit.

Source

Thrown at compressor/seata-compressor-bzip2/src/main/java/org/apache/seata/compressor/bzip2/BZip2Util.java:62

            throw new RuntimeException("BZip2 compress error", e);
        }
    }

    public static byte[] decompress(byte[] bytes) {
        if (bytes == null) {
            throw new NullPointerException("bytes is null");
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        try (CBZip2InputStream bzip2 = new CBZip2InputStream(bis)) {
            byte[] buffer = new byte[BUFFER_SIZE];
            int n;
            while ((n = bzip2.read(buffer)) > -1) {
                out.write(buffer, 0, n);
            }
            return out.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("BZip2 decompress error", e);
        }
    }
}

View on GitHub (pinned to e01f97c6db)

Solutions

  1. Make compressor configuration symmetric on both peers (same seata transport/undo compressor id) and restart both sides after changing it.
  2. Check the first two bytes of the payload — a valid bzip2 stream starts with 'B' 'Z' (0x42 0x5A); if not, the data was not bzip2-compressed.
  3. Verify the payload length matches what the sender logged (detect truncation).
  4. Catch RuntimeException around decompress and surface the IOException cause for precise diagnosis.

Example fix

// before
 byte[] raw = BZip2Util.decompress(body);

// after
 if (body.length < 2 || body[0] != 'B' || body[1] != 'Z') {
     throw new IOException("payload is not bzip2 (bad magic) — check compressor config on both peers");
 }
 try {
     byte[] raw = BZip2Util.decompress(body);
 } catch (RuntimeException e) {
     throw new IOException("bzip2 decompress failed", e.getCause());
 }
Defensive patterns

Strategy: try-catch

Validate before calling

// bzip2 streams start with magic 'BZ'
public static boolean looksLikeBzip2(byte[] data) {
    return data != null && data.length >= 2
        && data[0] == 'B' && data[1] == 'Z';
}

Try / catch

try {
    return BZip2Util.decompress(bytes);
} catch (RuntimeException e) {
    Throwable cause = e.getCause(); // original IOException
    throw new IOException("bzip2 decompress failed (corrupt or wrong-compressor payload)", cause);
}

Prevention

When it happens

Trigger: decompress(bytes) where bytes was produced by gzip/deflater/zstd (compressor id mismatch between endpoints), by bzip2 without the leading 'BZ' magic (some CLI bzip2 variants differ), truncated by a size-limited channel, or double-encoded; also raw data passed where compressed data was expected.

Common situations: Client configured compressor: gzip while server expects bzip2 (or vice versa) after a config change rolled out partially; messages routed through proxies that mangle binary payloads; undo logs written uncompressed then read with bzip2 enabled; version drift in commons-compress changing stream validation strictness.

Related errors


AI-assisted analysis of apache/incubator-seata@e01f97c6db (2026-08-14). Data as JSON: /api/errors/b453bcc1839c7aaf. Report an issue: GitHub.