{"record":{"id":"c0c47e8d0240b776","repo":"hashicorp/nomad","slug":"failed-to-finalize-snapshot-v","errorCode":null,"errorMessage":"failed to finalize snapshot: %v","messagePattern":"failed to finalize snapshot: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"helper/snapshot/archive.go","lineNumber":163,"sourceCode":"\tvar shaBuffer bytes.Buffer\n\tif err := hl.Encode(&shaBuffer); err != nil {\n\t\treturn fmt.Errorf(\"failed to encode snapshot hashes: %v\", err)\n\t}\n\tif err := archive.WriteHeader(&tar.Header{\n\t\tName:    \"SHA256SUMS\",\n\t\tMode:    0600,\n\t\tSize:    int64(shaBuffer.Len()),\n\t\tModTime: now,\n\t}); err != nil {\n\t\treturn fmt.Errorf(\"failed to write snapshot hashes header: %v\", err)\n\t}\n\tif _, err := io.Copy(archive, &shaBuffer); err != nil {\n\t\treturn fmt.Errorf(\"failed to write snapshot metadata: %v\", err)\n\t}\n\n\t// Finalize the archive.\n\tif err := archive.Close(); err != nil {\n\t\treturn fmt.Errorf(\"failed to finalize snapshot: %v\", err)\n\t}\n\n\treturn nil\n}\n\n// read takes a reader and extracts the snapshot metadata and the snapshot\n// itself, and also checks the integrity of the data. You must arrange to call\n// Close() on the returned object or else you will leak a temporary file.\nfunc read(in io.Reader, metadata *raft.SnapshotMeta, snap io.Writer) error {\n\t// Start a new tar reader.\n\tarchive := tar.NewReader(in)\n\n\t// Create a hash list that we will use to compare with the SHA256SUMS\n\t// file in the archive.\n\thl := newHashList()\n\n\t// Populate the hashes for all the files we expect to see. The check at\n\t// the end will make sure these are all present in the SHA256SUMS file","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/snapshot/archive.go#L145-L181","documentation":"This error wraps the failure of tar.Writer.Close() while finalizing the snapshot tar archive in helper/snapshot/archive.go write(). Close() flushes any buffered data and writes the tar end-of-archive blocks; if the underlying output writer (out io.Writer) returns an error there (e.g. disk full on a file sink, closed pipe, broken connection to storage), it is surfaced as 'failed to finalize snapshot'. All prior writes may have succeeded, so the failure is purely at archive-finalization/flush time on the destination writer.","triggerScenarios":"Calling snapshot write()/Store.Store/TakeSnapshot where the destination io.Writer errors during Close: writing to a full disk, a closed or broken pipe (e.g. HTTP response writer closed client-side mid-snapshot), a network writer (S3/consul sink) timing out during flush, or an os.File whose write fails at the tail.","commonSituations":"Disk quota/full filesystem on the node storing the snapshot; client disconnects while downloading a snapshot via the Consul HTTP API; transient network failure to a remote snapshot sink; output file handle closed prematurely by surrounding code.","solutions":["Check free disk space / write permissions on the snapshot destination and retry after freeing space","If streaming to a remote sink, verify the sink connection and retry the snapshot operation","Inspect the wrapped %v error for the true underlying cause and fix that writer","If writing to an HTTP response, ensure the client keeps the connection open for the full snapshot download"],"exampleFix":"// before\nf, _ := os.Create(path)\nsnapshot.Store(f)\n// after\nf, err := os.Create(path)\nif err != nil { return err }\ndefer f.Close()\nif err := snapshot.Store(f); err != nil {\n    return fmt.Errorf(\"snapshot write failed (check disk space/permissions on %s): %w\", path, err)\n}","handlingStrategy":"try-catch","validationCode":"// Go has no pre-call check, but validate the sink before writing:\ninfo, err := os.Stat(targetDir)\nif err != nil || !info.IsDir() {\n    return fmt.Errorf(\"snapshot target dir invalid: %v\", err)\n}\n// ensure writable\nprobe, err := os.CreateTemp(targetDir, \"snap-probe-*\")\nif err != nil {\n    return fmt.Errorf(\"snapshot target not writable: %v\", err)\n}\nprobe.Close()\nos.Remove(probe.Name())","typeGuard":"// errors.As to inspect the underlying writer failure\nfunc unwrapFinalizeErr(err error) error {\n    if err != nil && strings.Contains(err.Error(), \"failed to finalize snapshot\") {\n        var inner error\n        if _, scan := fmt.Sscanf(err.Error(), \"failed to finalize snapshot: %v\", &inner); scan == nil {\n            return inner\n        }\n    }\n    return err\n}","tryCatchPattern":"if err := snapshot.Store(out); err != nil {\n    if strings.Contains(err.Error(), \"failed to finalize snapshot\") {\n        log.Error(\"snapshot finalize failed (disk/network on destination)\", \"err\", err)\n        // free space / reset sink, then retry\n        return retryStore()\n    }\n    return err\n}","preventionTips":["Monitor free disk space on snapshot destinations and alert before it runs out","Keep the HTTP client/connection open until the snapshot stream is fully received","Validate sink connectivity to remote snapshot storage before taking snapshots","Always check errors on the underlying writer, not just the snapshot call"],"tags":["go","io","snapshot","tar","disk"],"backgroundTag":"snapshot-archive-write-failed","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}