{"record":{"id":"a07c39510a7761e3","repo":"benbjohnson/litestream","slug":"download-snapshot-w","errorCode":null,"errorMessage":"download snapshot: %w","messagePattern":"download snapshot: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"replica.go","lineNumber":1147,"sourceCode":"\n\tr.Logger().Debug(\"found v0.3.x WAL segments\", \"n\", len(segments))\n\n\t// Create parent directory if it doesn't exist.\n\tvar dirInfo os.FileInfo\n\tif db := r.DB(); db != nil {\n\t\tdirInfo = db.DirInfo()\n\t}\n\tif err := internal.MkdirAll(filepath.Dir(opt.OutputPath), dirInfo); err != nil {\n\t\treturn fmt.Errorf(\"create parent directory: %w\", err)\n\t}\n\n\t// Create temp file for restore.\n\ttmpPath := opt.OutputPath + \".tmp\"\n\tdefer func() { _ = os.Remove(tmpPath) }()\n\n\t// Download and decompress snapshot.\n\tif err := r.downloadSnapshotV3(ctx, client, snapshot.Generation, snapshot.Index, tmpPath); err != nil {\n\t\treturn fmt.Errorf(\"download snapshot: %w\", err)\n\t}\n\n\t// Apply WAL segments.\n\tif err := r.applyWALSegmentsV3(ctx, client, snapshot.Generation, snapshot.Index, segments, tmpPath); err != nil {\n\t\treturn fmt.Errorf(\"apply WAL segments: %w\", err)\n\t}\n\n\t// Rename to final path.\n\tif err := os.Rename(tmpPath, opt.OutputPath); err != nil {\n\t\treturn fmt.Errorf(\"rename to output path: %w\", err)\n\t}\n\tif err := internal.FsyncDir(filepath.Dir(opt.OutputPath)); err != nil {\n\t\treturn fmt.Errorf(\"sync restore output dir: %w\", err)\n\t}\n\n\tif opt.IntegrityCheck != IntegrityCheckNone {\n\t\tif err := checkIntegrity(ctx, opt.OutputPath, opt.IntegrityCheck); err != nil {\n\t\t\tif ctx.Err() == nil {","sourceCodeStart":1129,"sourceCodeEnd":1165,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/replica.go#L1129-L1165","documentation":"RestoreV3 downloads and decompresses the selected v0.3.x snapshot into a temporary file via r.downloadSnapshotV3; any failure (network read, storage get, decompression, checksum) is wrapped as 'download snapshot: %w'. The temp file is removed on failure so no partial output remains at OutputPath.","triggerScenarios":"Calling Replica.Restore when fetching the snapshot object from the replica client fails: backend read error mid-stream, context cancellation/timeout during a large download, corrupted snapshot data that fails decompression, or the snapshot object was deleted between listing and download.","commonSituations":"Large databases and short HTTP timeouts/proxy idle cutoffs; flaky VPN/network during DR; S3 throttling on big GETs; corrupted snapshot object in storage; restore interrupted by ctx cancellation from the caller.","solutions":["Inspect the wrapped cause to distinguish network error vs decompression/corruption error","Retry the restore with a longer timeout / more stable connection; downloads are idempotent (temp file is discarded)","Verify the snapshot object's integrity in the backend; if corrupted, restore from an earlier snapshot via RestoreOptions.Timestamp","Increase client timeouts or use a replica client closer to the storage region"],"exampleFix":"// before\nctx := context.Background()\nerr := replica.Restore(ctx, opt) // times out on big snapshot\n// after\nctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute)\ndefer cancel()\nerr := replica.Restore(ctx, opt)","handlingStrategy":"retry","validationCode":"// preflight: HEAD the snapshot object to ensure it is downloadable and sized as expected\nif _, err := client.SnapshotsV3(ctx, generation); err != nil {\n    return fmt.Errorf(\"snapshot not reachable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := replica.Restore(ctx, opt); err != nil {\n    if strings.Contains(err.Error(), \"download snapshot\") {\n        log.Printf(\"snapshot download failed, cause=%v\", errors.Unwrap(err))\n        return retryWithBackoff(ctx, 3, func() error { return replica.Restore(ctx, opt) })\n    }\n    return err\n}","preventionTips":["Use a context timeout sized for the largest expected snapshot, not the default","Run restores from a host with reliable bandwidth to the storage region","Periodically verify snapshot integrity in the replica (restore drills)","Handle context cancellation explicitly so partial downloads are retried, not mistaken for corruption"],"tags":["go","restore","network","storage","download","timeout"],"backgroundTag":"network-request-failed","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}