nats-io/nats-server · error
short write on checksum (%d != %d)
Error message
short write on checksum (%d != %d)
What it means
Returned when output.Write(checksum) succeeds but writes fewer bytes than checksumSize, indicating a short write. A truncated checksum would make the block undetectably corrupt on read, so the library rejects it.
Source
Thrown at server/filestore.go:14533
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.
if n, err := io.CopyN(writer, input, bodyLen); err != nil {
return nil, fmt.Errorf("error writing to compression writer: %w", err)
} else if n != bodyLen {
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))View on GitHub (pinned to 3a66a489d2)
Solutions
- If output is a custom writer, make Write loop until the full slice is consumed or return an error
- Use bytes.Buffer or another writer that always writes fully for the checksum append
- Treat this as a bug in the output writer; replace it with a stdlib buffer
Example fix
// before (custom writer may short-write)
output = myWriter{}
// after
output = bytes.NewBuffer(make([]byte, 0, bodyLen+checksumSize)) Defensive patterns
Strategy: validation
Validate before calling
if cw, ok := output.(interface{ Write([]byte) (int, error) }); ok { if n, err := cw.Write([]byte("x")); err != nil || n != 1 { /* writer may short-write */ } } Type guard
func writesFully(w io.Writer) bool { b := bytes.NewBuffer(nil); n, err := w.Write(make([]byte, 16)); return err == nil && n == 16 && (b == nil) } Try / catch
_, err := alg.Compress(body)
if err != nil && strings.Contains(err.Error(), "short write on checksum") {
// replace custom writer with bytes.Buffer and retry
} Prevention
- Never pass custom io.Writer implementations that short-write without error
- Prefer bytes.Buffer as the compression output target
- Wrap any custom writer with a write-full loop adapter
When it happens
Trigger: The output writer accepts the checksum slice but reports n != checksumSize during StoreCompression block compression.
Common situations: Custom io.Writer implementations that legally return short writes without error (io.Writer contract permits this) — most standard writers never do this.
Related errors
- error writing checksum: %w
- ErrClosed
- ErrInvalidArchive
- ErrNegativeEntrySize
- failed to read v2 signature: %w
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/00057c65d3c2faf7.
Report an issue: GitHub.