nats-io/nats-server · error
uncompressed buffer is too short
Error message
uncompressed buffer is too short
What it means
StoreCompression.Compress() requires the input buffer to be at least checksumSize bytes long, because the format keeps the trailing checksum uncompressed and only compresses the body before it. A buffer shorter than the checksum can never be a valid block, so it refuses. From server/filestore.go.
Source
Thrown at server/filestore.go:14501
c.OriginalSize = 0
if len(b) < 5 { // 4 + min 1 for uvarint uint64
return 0, nil
}
if b[0] != 'c' || b[1] != 'm' || b[2] != 'p' {
return 0, nil
}
var n int
c.Algorithm = StoreCompression(b[3])
c.OriginalSize, n = binary.Uvarint(b[4:])
if n <= 0 {
return 0, fmt.Errorf("metadata incomplete")
}
return 4 + n, nil
}
func (alg StoreCompression) Compress(buf []byte) ([]byte, error) {
if len(buf) < checksumSize {
return nil, fmt.Errorf("uncompressed buffer is too short")
}
bodyLen := int64(len(buf) - checksumSize)
var output bytes.Buffer
var writer io.WriteCloser
switch alg {
case NoCompression:
return buf, nil
case S2Compression:
writer = s2.NewWriter(&output)
default:
return nil, fmt.Errorf("compression algorithm not known")
}
input := bytes.NewReader(buf[:bodyLen])
checksum := buf[bodyLen:]
// Compress the block content, but don't compress the checksum.
// We will preserve it at the end of the block as-is.View on GitHub (pinned to 3a66a489d2)
Solutions
- Ensure every buffer passed to Compress ends with the checksum (len >= checksumSize) before compression
- Fix the block builder to append the checksum even for empty/small bodies
- If compressing raw data yourself, don't route it through StoreCompression — compress only the body region
- Add a pre-call length check so callers fail fast with context
Example fix
// before
alg.Compress(buf) // panics-ish: uncompressed buffer is too short
// after
if len(buf) < checksumSize {
return fmt.Errorf("block %d bytes too short to compress", len(buf))
}
alg.Compress(buf) Defensive patterns
Strategy: validation
Validate before calling
if len(buf) < checksumSize {
return fmt.Errorf("need at least %d bytes, got %d", checksumSize, len(buf))
}
alg.Compress(buf) Type guard
func compressible(buf []byte) bool { return len(buf) >= checksumSize } Try / catch
out, err := alg.Compress(buf)
if err != nil && strings.Contains(err.Error(), "too short") {
// caller passed a malformed block; fix builder
return errMalformedBlock
} Prevention
- Always append the checksum before compression
- Centralize block building in one function
- Unit-test compression with empty and minimum-size blocks
- Assert len(buf) >= checksumSize in block constructors
When it happens
Trigger: Calling Compress (or a code path that compresses blocks) with a buffer smaller than checksumSize — e.g. an empty or nearly-empty block passed to the compression path by mistake.
Common situations: Bugs in custom tooling that calls the store's compression helpers directly; a block-building routine that produced an empty body without the checksum suffix; tests feeding synthetic buffers.
Related errors
- failed to read original block from disk: %w
- failed to read existing metadata header: %w
- failed to decompress original block: %w
- failed to compress block: %w
- bad consumer config
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/5276e908d832c84b.
Report an issue: GitHub.