{"record":{"id":"8170ab5865523494","repo":"nats-io/nats-server","slug":"failed-to-read-existing-metadata-header-w","errorCode":null,"errorMessage":"failed to read existing metadata header: %w","messagePattern":"failed to read existing metadata header: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/filestore.go","lineNumber":7985,"sourceCode":"\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read original block from disk: %w\", err)\n\t}\n\n\t// If the block is encrypted then we will need to decrypt it before\n\t// doing anything. We always encrypt after compressing because then the\n\t// compression can be as efficient as possible on the raw data, whereas\n\t// the encrypted ciphertext will not compress anywhere near as well.\n\t// The block encryption also covers the optional compression metadata.\n\tif err = mb.encryptOrDecryptIfNeeded(origBuf); err != nil {\n\t\treturn err\n\t}\n\n\tmeta := &CompressionInfo{}\n\tif _, err := meta.UnmarshalMetadata(origBuf); err != nil {\n\t\t// An error is only returned here if there's a problem with parsing\n\t\t// the metadata. If the file has no metadata at all, no error is\n\t\t// returned and the algorithm defaults to no compression.\n\t\treturn fmt.Errorf(\"failed to read existing metadata header: %w\", err)\n\t}\n\tif meta.Algorithm == alg {\n\t\t// The block is already compressed with the chosen algorithm so there\n\t\t// is nothing else to do. This is not a common case, it is here only\n\t\t// to ensure we don't do unnecessary work in case something asked us\n\t\t// to recompress an already compressed block with the same algorithm.\n\t\treturn nil\n\t} else if alg != NoCompression {\n\t\t// The block is already compressed using some algorithm, so we need\n\t\t// to decompress the block using the existing algorithm before we can\n\t\t// recompress it with the new one.\n\t\tif origBuf, err = meta.Algorithm.Decompress(origBuf); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to decompress original block: %w\", err)\n\t\t}\n\t}\n\n\treturn mb.atomicOverwriteFile(origBuf, true)\n}","sourceCodeStart":7967,"sourceCodeEnd":8003,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/filestore.go#L7967-L8003","documentation":"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.","triggerScenarios":"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.","commonSituations":"Upgrading/downgrading across NATS versions with changed compression metadata layout; disk corruption; manually truncating or editing block files.","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"],"exampleFix":"// version mismatch scenario\nnats-server -v  # running 2.9.x\n// block written by 2.10.x — upgrade before recompressing\nsystemctl upgrade nats-server && systemctl restart nats-server","handlingStrategy":"validation","validationCode":"// Go: don't recompress blocks written by an incompatible server version\nif runningVersion.Major() != writtenVersion.Major() {\n    return fmt.Errorf(\"align nats-server version (%s) with datadir writer (%s) before recompress\",\n        runningVersion, writtenVersion)\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"failed to read existing metadata header\") {\n    // corrupt metadata: restore block from backup or recreate stream\n    return restoreBlockFromBackup(blockPath)\n}","preventionTips":["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"],"tags":["jetstream","filestore","compression","metadata-corruption","recompression"],"backgroundTag":"compression-metadata-corrupt","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}