Limits and partial reads
A limit on the way out
A megabyte of zeros gzips to about a thousand bytes. That ratio is the whole point of compression, and also the whole point of a zip bomb. So decompress stops at 256 MiB by default, and you can set it lower:
decompress("deflate", bomb, { container: "gzip", limit: 100_000 });
// LimitError: deflate: output passes the limit of 100000 bytes
The check happens before a byte lands, not after the buffer has grown. A size the stream claims up front only sizes the first buffer, and never past the limit or 64 MiB. A liar gets a small buffer and the same error.
identify and peel take the same limit, applied to every attempt.
The tools are stricter
| Bound | Value |
|---|---|
| Output of one stream | 64 MiB |
| Decompressed bytes shown in one answer | 16 KiB by default, up to 1 MiB with length |
| Input to one call | 4,000,000 characters of base64, hex or text |
Layers peel takes off | 10 |
Long output comes in windows. The header says showing 0 to 16384; pass offset for the rest, and the model asks for the next window with offset.
Partial reads
A stream cut in half still holds half the data. Ask for it:
decompress("deflate", cut, { container: "gzip", partial: true });
// { bytes: …everything before the cut…,
// details: { error: "deflate: gzip member ends before its CRC-32 and size" } }
Without partial, the same bytes ride on the error:
try {
decompress("deflate", cut, { container: "gzip" });
} catch (error) {
if (error instanceof DecompressError) error.partial; // the same bytes
}
Every format writes as it goes, so what comes out before the damage is real output, not a guess. A wrong checksum works the same way: the bytes are all there, the check just failed. LZMA2 decodes a cut chunk as far as it gets. Inflate never writes a block end it didn't actually read.
Errors
| Error | When |
|---|---|
DecompressError | The stream is broken. Carries format, offset and partial |
ChecksumError | A checksum or a stored size doesn't match. A DecompressError too |
LimitError | The output passes limit |
UnsupportedError | The stream uses something the format allows and this package doesn't do, such as a zstd dictionary |
UnknownFormatError | No format by that name. gzip, xz and friends get pointed to their family |
InvalidOptionError | An option out of range or for another container |
All of them extend CompressionError, so one catch takes them all.