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

  1. Check the wrapped decompression cause and whether the block's compression flag matches the data
  2. Reset the affected stream (delete its block files) to force recreation if data loss is acceptable
  3. Restore the store directory from a consistent offline backup
  4. 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

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


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/83ab0e1eb23a9b74. Report an issue: GitHub.