nats-io/nats-server · error
compressed buffer is too short
Error message
compressed buffer is too short
What it means
StoreCompression.Decompress requires the trailing checksum to be present: a buffer shorter than checksumSize cannot even contain the checksum, so it cannot be a valid compressed block. Returned before any decompression is attempted.
Source
Thrown at server/filestore.go:14541
return nil, fmt.Errorf("short write on body (%d != %d)", n, bodyLen)
}
if err := writer.Close(); err != nil {
return nil, fmt.Errorf("error closing compression writer: %w", err)
}
// Now add the checksum back onto the end of the block.
if n, err := output.Write(checksum); err != nil {
return nil, fmt.Errorf("error writing checksum: %w", err)
} else if n != checksumSize {
return nil, fmt.Errorf("short write on checksum (%d != %d)", n, checksumSize)
}
return output.Bytes(), nil
}
func (alg StoreCompression) Decompress(buf []byte) ([]byte, error) {
if len(buf) < checksumSize {
return nil, fmt.Errorf("compressed buffer is too short")
}
bodyLen := int64(len(buf) - checksumSize)
input := bytes.NewReader(buf[:bodyLen])
var reader io.ReadCloser
switch alg {
case NoCompression:
return buf, nil
case S2Compression:
reader = io.NopCloser(s2.NewReader(input))
default:
return nil, fmt.Errorf("compression algorithm not known")
}
// Decompress the block content. The checksum isn't compressed so
// we can preserve it from the end of the block as-is.
checksum := buf[bodyLen:]
output, err := io.ReadAll(reader)View on GitHub (pinned to 3a66a489d2)
Solutions
- Verify the source of the buffer: check the block file was fully written (length + checksum)
- Don't strip the checksum from the buffer before calling Decompress
- Check the filestore for truncated blocks and re-fetch/re-sync the affected block
- Log the buffer length to confirm it is below checksumSize and trace where truncation happens
Example fix
// before
out, err := alg.Decompress(buf[:bodyOnly])
// after
if len(buf) < checksumSize { return ErrCorruptBlock }
out, err := alg.Decompress(buf) Defensive patterns
Strategy: validation
Validate before calling
if len(buf) < checksumSize { return fmt.Errorf("cannot decompress: buffer %d < checksum size", len(buf)) } Type guard
func isDecompressable(buf []byte) bool { return len(buf) >= checksumSize } Try / catch
out, err := alg.Decompress(buf)
if err != nil {
if strings.Contains(err.Error(), "compressed buffer is too short") {
// block source truncated; refetch or resync the block
}
return err
} Prevention
- Never strip the trailing checksum before calling Decompress
- Validate block file sizes when reading from storage (len == declared bodyLen + checksumSize)
- Detect truncation at the file-read layer and resync from a peer/backup
When it happens
Trigger: Calling Decompress (or any filestore read path that decompresses a stored block) with a byte slice whose len < checksumSize — e.g. an empty slice, a truncated read, or a corrupted/zero-length stored block.
Common situations: Truncated filestore block files after a crash, reading past a partially written block, a bug slicing off the checksum before calling Decompress, or feeding Decompress arbitrary bytes it was never meant to receive.
Related errors
- failed to decompress original block: %w
- error reading compression reader: %w
- invalid retained message flags
- failed to decompress block: %w
- loading encryption for block %d failed: %w
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/b0c865f30a113afd.
Report an issue: GitHub.