can1357/oh-my-pi · error · ArchiveError
${error instanceof Error ? error.message : String(error)}
Error message
${error instanceof Error ? error.message : String(error)} What it means
zstdDecompress wraps any failure from the underlying async zstd decoder into an ArchiveError carrying the native decoder's message. This is the surface for all zstd frame problems: corrupt frames, magic mismatch, exceeding maxOutputLength, or unsupported frame parameters.
Source
Thrown at packages/utils/src/ar/codecs/zstd.ts:18
import { promisify } from "node:util";
import * as zlib from "node:zlib";
import { ArchiveError } from "../error";
const zstdCompressAsync = promisify(zlib.zstdCompress);
const zstdDecompressAsync = promisify(zlib.zstdDecompress);
/** zstd frame magic: 28 b5 2f fd. */
export function isZstd(bytes: Uint8Array): boolean {
return bytes.byteLength >= 4 && bytes[0] === 0x28 && bytes[1] === 0xb5 && bytes[2] === 0x2f && bytes[3] === 0xfd;
}
/** Decompress one zstd frame, bounded to `maxOutput` bytes. */
export async function zstdDecompress(bytes: Uint8Array, maxOutput: number): Promise<Uint8Array> {
try {
return await zstdDecompressAsync(bytes, { maxOutputLength: Math.max(maxOutput, 1) });
} catch (error) {
throw new ArchiveError(error instanceof Error ? error.message : String(error));
}
}
/** Compress bytes as one zstd frame (tar.zst writing). */
export function zstdCompress(bytes: Uint8Array): Promise<Uint8Array> {
return zstdCompressAsync(bytes);
}
View on GitHub (pinned to 9690622007)
Solutions
- Verify the input starts with the zstd magic (0x28 B5 2F FD) before calling
- Raise maxOutput if the native message indicates the output limit was hit and the input is trusted
- Re-download/re-extract the file if the message indicates corruption
- Ensure you are using the right codec for the file (zstd vs gzip vs xz)
Example fix
// before
await zstdDecompress(bytes, 10 * 1024 * 1024); // bombs out on large frames
// after
if (!(bytes[0] === 0x28 && bytes[1] === 0xb5 && bytes[2] === 0x2f && bytes[3] === 0xfd)) throw new Error('not zstd');
await zstdDecompress(bytes, 256 * 1024 * 1024); Defensive patterns
Strategy: validation
Validate before calling
function isZstdFrame(b: Uint8Array): boolean {
return b.byteLength >= 4 && b[0] === 0x28 && b[1] === 0xb5 && b[2] === 0x2f && b[3] === 0xfd;
}
if (!isZstdFrame(bytes)) throw new Error('not a zstd frame'); Type guard
function isZstdFrame(b: Uint8Array): boolean {
return b.byteLength >= 4 && b[0] === 0x28 && b[1] === 0xb5 && b[2] === 0x2f && b[3] === 0xfd;
} Try / catch
try {
return await zstdDecompress(bytes, maxOutput);
} catch (err) {
if (err instanceof ArchiveError) {
if (/output/i.test(err.message)) return null; // hit maxOutput: bomb or limit too low
return null; // corrupt/invalid frame
}
throw err;
} Prevention
- Check the zstd magic bytes before decoding
- Size maxOutput to the expected uncompressed data plus headroom
- Detect codec by magic bytes (xz 0xFD '7zXZ', gzip 0x1F 0x8B, zstd 0x28 B5 2F FD) rather than filename
When it happens
Trigger: Calling zstdDecompress on bytes that are not a valid zstd frame; a frame whose decompressed size exceeds maxOutputLength; truncated .tar.zst or .zst payloads.
Common situations: Corrupt uploads; decompression-bomb protection tripping maxOutputLength; files with wrong extension decompressed with the wrong codec; zstd frames produced with dictionaries or parameters the decoder rejects.
Related errors
- Invalid ARJ method-4 compressed data: truncated bitstream
- Invalid ARJ method-4 compressed data: non-zero trailing bits
- Invalid ARJ method-4 compressed data: match exceeds declared
- Invalid ARJ method-4 compressed data: history distance is ou
- Invalid CAB archive: MSZIP decompression failed${error insta
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/660fa20416e3ca53.
Report an issue: GitHub.