JuliusBrussee/caveman · error · ErrDecompressedTooLarge
objectstore: decompressed payload exceeds limit
Error message
objectstore: decompressed payload exceeds limit
What it means
ErrDecompressedTooLarge is a sentinel error returned by DecompressLimit (and the default decompress path for CompressionNone) when a payload would exceed the caller's maxBytes ceiling. It is raised before allocation blowup for compressed data and after a length check for uncompressed data, protecting against decompression-bomb attacks and accidental oversized reads.
Solutions
- Call DecompressLimit with the trusted plaintext size from your metadata rather than relying on the default
- If the data is genuinely needed, raise maxBytes deliberately for that call path
- Verify the object's expected size before fetch; reject oversized uploads at ingest time
- Check that CompressionNone payloads were stored correctly (an oversized raw payload may indicate a mis-tagged object)
Example fix
// before data, err := objectstore.DecompressLimit(blob, objectstore.DefaultMaxDecompressedBytes) // after maxBytes := int64(obj.Metadata.PlaintextSize) // trusted, validated upstream data, err := objectstore.DecompressLimit(blob, maxBytes)
Defensive patterns
Strategy: try-catch
Validate before calling
if int64(len(expectedPlaintext)) > maxBytes {
return errors.New("payload exceeds decompression ceiling")
}
// prefer: maxBytes from trusted metadata, not the 128 MiB default Try / catch
data, err := objectstore.DecompressLimit(blob, maxBytes)
if errors.Is(err, objectstore.ErrDecompressedTooLarge) {
return fmt.Errorf("object exceeds %d bytes after decompression", maxBytes)
}
if err != nil {
return err
} Prevention
- Pass metadata-validated plaintext sizes to DecompressLimit instead of relying on the default
- Reject oversized compressed uploads at ingest to prevent decompression bombs
- Always check errors with errors.Is against ErrDecompressedTooLarge
When it happens
Trigger: Decompressing a zstd payload whose expanded size exceeds maxBytes; passing an uncompressed (CompressionNone/"") payload longer than maxBytes; using DefaultMaxDecompressedBytes (128 MiB) implicitly and reading an object larger than that.
Common situations: User-supplied compressed uploads (decompression bombs), reading an old object stored before size limits were introduced, decompressing with the default limit instead of a trusted metadata-driven limit.
Understand the failure class
Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.
Related errors
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/2ab92b4d4c3d4200.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/objectstore/compress.go:26
"io"
"github.com/klauspost/compress/zstd"
)
// Compression names the supported codecs; they mirror the artifacts.compression
// CHECK constraint (none|gzip|zstd). An unknown codec fails closed.
const (
CompressionNone = "none"
CompressionGzip = "gzip"
CompressionZstd = "zstd"
)
var (
zstdEnc, _ = zstd.NewWriter(nil)
// ErrDecompressedTooLarge is returned before a compressed payload can
// expand beyond the caller's plaintext ceiling.
ErrDecompressedTooLarge = errors.New("objectstore: decompressed payload exceeds limit")
)
// DefaultMaxDecompressedBytes protects callers that do not have trusted size
// metadata. Callers with an expected plaintext size should use
// DecompressLimit with the smaller, metadata-validated limit.
const DefaultMaxDecompressedBytes int64 = 128 << 20
// Compress encodes data with the named codec. "none" returns data unchanged.
func Compress(codec string, data []byte) ([]byte, error) {
switch codec {
case CompressionNone, "":
return data, nil
case CompressionGzip:
var buf bytes.Buffer
zw := gzip.NewWriter(&buf)
if _, err := zw.Write(data); err != nil {
return nil, fmt.Errorf("gzip: %w", err)
}View on GitHub (pinned to 3ee70a1026)