{"record":{"id":"f8a38dad74300bac","repo":"benbjohnson/litestream","slug":"apply-wal-segments-w","errorCode":null,"errorMessage":"apply WAL segments: %w","messagePattern":"apply WAL segments: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"replica.go","lineNumber":1152,"sourceCode":"\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 {\n\t\t\t\t_ = os.Remove(opt.OutputPath)\n\t\t\t\t_ = os.Remove(opt.OutputPath + \"-shm\")\n\t\t\t\t_ = os.Remove(opt.OutputPath + \"-wal\")\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"post-restore integrity check: %w\", err)","sourceCodeStart":1134,"sourceCodeEnd":1170,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/replica.go#L1134-L1170","documentation":"After the snapshot is downloaded, RestoreV3 replays the filtered WAL segments into the temp database via r.applyWALSegmentsV3; any failure is wrapped as 'apply WAL segments: %w'. This step rolls the snapshot forward to the latest (or requested timestamp) transaction; failures mean the restore cannot reach the target point-in-time.","triggerScenarios":"Calling Replica.Restore when applying WAL segments fails: a WAL segment object is missing or corrupted in storage, segments are out of order / gaps in the WAL chain, decompression of a segment fails, or a network error occurs while downloading segments mid-replay.","commonSituations":"Bucket lifecycle rules deleting old WAL segments needed by the replay; interrupted replication leaving gaps in the WAL chain; corrupted or truncated WAL objects; restore of a very old snapshot whose later WALs were compacted/removed under v0.3.x semantics.","solutions":["Inspect the wrapped cause to identify the failing segment (index/order/corruption)","Pick an earlier snapshot or later timestamp (RestoreOptions.Timestamp) that has a complete WAL chain","Verify WAL segment objects exist and are intact in the generation's WAL prefix; re-replicate if the replica is still live","Retry the restore to rule out transient network errors during segment downloads"],"exampleFix":"// before\nvar ts time.Time // latest — replay needs full WAL chain\nerr := replica.Restore(ctx, litestream.RestoreOptions{OutputPath: p, Timestamp: ts})\n// after\nsnapshotTime := time.Date(2026, 9, 1, 12, 0, 0, 0, time.UTC) // target point with intact WALs\nerr := replica.Restore(ctx, litestream.RestoreOptions{OutputPath: p, Timestamp: snapshotTime})","handlingStrategy":"fallback","validationCode":"// preflight: confirm a contiguous WAL chain exists for the snapshot's generation\nsegments, err := client.WALSegmentsV3(ctx, generation)\nif err != nil {\n    return err\n}\nfiltered := litestream.FilterWALSegments(segments, snapshotIndex, timestamp) // or equivalent ordering check\nif len(filtered) == 0 {\n    return fmt.Errorf(\"no WAL segments available for replay\")\n}","typeGuard":null,"tryCatchPattern":"if err := replica.Restore(ctx, opt); err != nil {\n    if strings.Contains(err.Error(), \"apply WAL segments\") {\n        log.Printf(\"WAL replay failed, cause=%v; trying earlier snapshot\", errors.Unwrap(err))\n        opt.Timestamp = opt.Timestamp.Add(-24 * time.Hour) // fall back to an earlier point\n        return replica.Restore(ctx, opt)\n    }\n    return err\n}","preventionTips":["Disable storage lifecycle rules that delete WAL segments still needed by retained snapshots","Keep retention >= your required point-in-time recovery window","Run scheduled restore tests to detect WAL gaps before a real disaster","Fix replication lags promptly so the WAL chain never has prolonged gaps"],"tags":["go","restore","wal","point-in-time","storage"],"backgroundTag":"resource-not-found","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"}