nats-io/nats-server · error
failed to decompress block: %w
Error message
failed to decompress block: %w
What it means
Wraps an error from mb.decompressIfNeeded while truncating the last block of a stream: the block was loaded from disk successfully but could not be decompressed/decrypted back to its original buffer. Indicates corrupted compressed bytes or a decompressor failure, so the truncate operation aborts.
Source
Thrown at server/filestore.go:6884
purged++
bytes += uint64(rl)
}
}
}
// If the block is compressed/encrypted then we have to load it into memory
// and decompress/decrypt it, truncate it and then write it back out.
// Otherwise, truncate the file itself and close the descriptor.
if mb.cmp != NoCompression || mb.bek != nil {
buf, err := mb.loadBlock(nil)
if err != nil {
return 0, 0, fmt.Errorf("failed to load block from disk: %w", err)
}
if err = mb.encryptOrDecryptIfNeeded(buf); err != nil {
return 0, 0, err
}
if buf, err = mb.decompressIfNeeded(buf); err != nil {
return 0, 0, fmt.Errorf("failed to decompress block: %w", err)
}
buf = buf[:eof]
copy(mb.lchk[0:], buf[len(buf)-checksumSize:])
// We did decompress but don't recompress the truncated buffer here since we're the last block
// and would otherwise have compressed data and allow to write uncompressed data in the same block.
if err = mb.atomicOverwriteFile(buf, false); err != nil {
return 0, 0, err
}
} else if mb.mfd != nil {
if err = mb.mfd.Truncate(eof); err != nil {
return 0, 0, err
}
if err = mb.mfd.Sync(); err != nil {
return 0, 0, err
}
// Update our checksum.
var lchk [8]byte
if _, err = mb.mfd.ReadAt(lchk[:], eof-8); err != nil {View on GitHub (pinned to 3a66a489d2)
Solutions
- Check the wrapped decompression cause and whether the block's compression flag matches the data
- Reset the affected stream (delete its block files) to force recreation if data loss is acceptable
- Restore the store directory from a consistent offline backup
- Align server versions across upgrades to keep compression formats consistent
Defensive patterns
Strategy: try-catch
Try / catch
// Go: distinguish load vs decompress failures when truncating last block
if _, _, err := truncateLastBlock(mb, eof); err != nil {
if strings.Contains(err.Error(), "failed to decompress block") {
// compressed payload corrupt: restore backup or reset stream
}
return err
} Prevention
- Keep compression settings and server versions consistent across upgrades
- Monitor storage for corruption; checksum volumes periodically
- Restore stores only from consistent offline backups
- Accept stream reset as recovery when no backup exists
When it happens
Trigger: Truncating a compressed last block (truncateMsgs) where the loaded buffer fails decompression — corrupt compressed payload, wrong compression algorithm recorded for the block, or truncated data with a stale checksum.
Common situations: Block files damaged by crashes or disk faults; mismatched server versions writing different compression formats; restored backups inconsistent with metadata.
Related errors
- failed to load block from disk: %w
- metadata incomplete
- message overrun
- sanity check failed
- rebuildState for block %d failed: %w
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/83ab0e1eb23a9b74.
Report an issue: GitHub.