{"record":{"id":"9f3797a1bccb4e0e","repo":"restic/restic","slug":"header-decoding-failed-w","errorCode":null,"errorMessage":"header decoding failed: %w","messagePattern":"header decoding failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/repository/pack/pack.go","lineNumber":138,"sourceCode":"\t\treturn p.err\n\t}\n\n\tif n != len(encryptedHeader) {\n\t\tp.err = errors.New(\"wrong number of bytes written\")\n\t\treturn p.err\n\t}\n\tp.bytes += uint(len(encryptedHeader))\n\n\treturn nil\n}\n\nfunc verifyHeader(k *crypto.Key, header []byte, expected []Blob) error {\n\t// do not offer a way to skip the pack header verification, as pack headers are usually small enough\n\t// to not result in a significant performance impact\n\n\tdecoded, hdrSize, err := List(k, bytes.NewReader(header), int64(len(header)))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"header decoding failed: %w\", err)\n\t}\n\tif hdrSize != uint32(len(header)) {\n\t\treturn fmt.Errorf(\"unexpected header size %v instead of %v\", hdrSize, len(header))\n\t}\n\tif len(decoded) != len(expected) {\n\t\treturn fmt.Errorf(\"pack header size mismatch\")\n\t}\n\tfor i := range decoded {\n\t\tif decoded[i] != expected[i] {\n\t\t\treturn fmt.Errorf(\"pack header entry mismatch got %v instead of %v\", decoded[i], expected[i])\n\t\t}\n\t}\n\treturn nil\n}\n\n// HeaderOverhead returns an estimate of the number of bytes written by a call to Finalize.\nfunc (p *Packer) HeaderOverhead() int {\n\treturn crypto.CiphertextLength(0) + binary.Size(uint32(0))","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/restic/restic/blob/a80be1478a4c537f8396e0db2b05120aa78f11e0/internal/repository/pack/pack.go#L120-L156","documentation":"The self-check performed right after encrypting a pack header failed at its first step: List() could not decode the header bytes that were just encrypted. A freshly encrypted header is by construction valid, so a decode failure practically means the bytes changed in memory between Seal and verify - the symptom restic associates with hardware faults or software bugs.","triggerScenarios":"Bit flips in RAM or CPU caches during the finalize path; failing storage for temporary buffers; a bug in the crypto or packer layer of that restic version.","commonSituations":"Large backups on unstable or overclocked machines; recurring finalize failures on one host; virtualization memory issues.","solutions":["Run a memory test (memtest86+) and verify system stability under load","Retry the backup; if it fails again on the same data, suspect hardware","Update to the latest restic release before further debugging","If reproducible on stable hardware, report it with the wrapped error and debug logs"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isHeaderDecodeFailure(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"header decoding failed\")\n}","tryCatchPattern":"if err := verifyHeader(k, encryptedHeader, blobs); err != nil {\n    if isHeaderDecodeFailure(err) {\n        // freshly encrypted data failed to decode: abort and collect hardware diagnostics\n        return abortWithDiagnostics(err)\n    }\n    return err\n}","preventionTips":["Treat any verifyHeader failure as a hardware alarm, not a data problem","Test RAM and cooling after the first occurrence","Report reproducible cases with the wrapped error to the restic tracker","Avoid aggressive RAM overclocking on machines producing backups"],"tags":["pack","header","corruption","hardware","fail-fast"],"backgroundTag":null,"analyzedSha":"a80be1478a4c537f8396e0db2b05120aa78f11e0","analyzedAt":"2026-08-15T15:30:29.928Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}