nats-io/nats-server · error
failed to read existing metadata header: %w
Error message
failed to read existing metadata header: %w
What it means
Returned during block recompression when UnmarshalMetadata cannot parse the compression metadata header at the end of the existing block file. A missing header is fine (defaults to no compression); this error means a header exists but is corrupt/unparseable, so the recompression cannot proceed safely.
Source
Thrown at server/filestore.go:7985
if err != nil {
return fmt.Errorf("failed to read original block from disk: %w", err)
}
// If the block is encrypted then we will need to decrypt it before
// doing anything. We always encrypt after compressing because then the
// compression can be as efficient as possible on the raw data, whereas
// the encrypted ciphertext will not compress anywhere near as well.
// The block encryption also covers the optional compression metadata.
if err = mb.encryptOrDecryptIfNeeded(origBuf); err != nil {
return err
}
meta := &CompressionInfo{}
if _, err := meta.UnmarshalMetadata(origBuf); err != nil {
// An error is only returned here if there's a problem with parsing
// the metadata. If the file has no metadata at all, no error is
// returned and the algorithm defaults to no compression.
return fmt.Errorf("failed to read existing metadata header: %w", err)
}
if meta.Algorithm == alg {
// The block is already compressed with the chosen algorithm so there
// is nothing else to do. This is not a common case, it is here only
// to ensure we don't do unnecessary work in case something asked us
// to recompress an already compressed block with the same algorithm.
return nil
} else if alg != NoCompression {
// The block is already compressed using some algorithm, so we need
// to decompress the block using the existing algorithm before we can
// recompress it with the new one.
if origBuf, err = meta.Algorithm.Decompress(origBuf); err != nil {
return fmt.Errorf("failed to decompress original block: %w", err)
}
}
return mb.atomicOverwriteFile(origBuf, true)
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Inspect the wrapped cause; compare the NATS version that wrote the block vs the running version
- If the block is expendable, let JetStream rebuild/remove it or re-create the stream and repopulate
- Restore the block file from backup and retry recompression
- Upgrade nats-server to the latest patch release where metadata parsing is more tolerant
Example fix
// version mismatch scenario nats-server -v # running 2.9.x // block written by 2.10.x — upgrade before recompressing systemctl upgrade nats-server && systemctl restart nats-server
Defensive patterns
Strategy: validation
Validate before calling
// Go: don't recompress blocks written by an incompatible server version
if runningVersion.Major() != writtenVersion.Major() {
return fmt.Errorf("align nats-server version (%s) with datadir writer (%s) before recompress",
runningVersion, writtenVersion)
} Try / catch
if err != nil && strings.Contains(err.Error(), "failed to read existing metadata header") {
// corrupt metadata: restore block from backup or recreate stream
return restoreBlockFromBackup(blockPath)
} Prevention
- Avoid mixing NATS versions across servers sharing a datadir (rolling upgrades: check compat)
- Never manually truncate/edit block files
- Enable filesystem checksums (ZFS/btrfs) to catch bit rot early
- Back up streams before compression migrations
When it happens
Trigger: RecompressMsgBlock on a block whose trailing metadata header bytes are corrupt — partial write from an unclean shutdown, bit rot, or an on-disk format written by a newer/older incompatible NATS version.
Common situations: Upgrading/downgrading across NATS versions with changed compression metadata layout; disk corruption; manually truncating or editing block files.
Related errors
- failed to read original block from disk: %w
- failed to decompress original block: %w
- failed to compress block: %w
- metadata incomplete
- uncompressed buffer is too short
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/8170ab5865523494.
Report an issue: GitHub.