benbjohnson/litestream · error
cannot calc restore plan: %w
Error message
cannot calc restore plan: %w
What it means
Returned by VFSFile.SetTargetTime when CalcRestorePlan cannot compute a valid sequence of LTX files reaching the requested timestamp. CalcRestorePlan walks the replica's file infos to find the snapshot+ generación of WAL-level LTX files covering the target time; planning errors mean the replica listing or metadata could not be turned into a restore plan.
Source
Thrown at vfs.go:1258
}
// Start compaction monitors if enabled
if f.compactor != nil && f.vfs != nil {
f.startCompactionMonitors()
}
return nil
}
// SetTargetTime rebuilds the page index to view the database at a specific time.
func (f *VFSFile) SetTargetTime(ctx context.Context, timestamp time.Time) error {
if timestamp.IsZero() {
return fmt.Errorf("target time required")
}
infos, err := CalcRestorePlan(ctx, f.client, 0, timestamp, f.logger)
if err != nil {
return fmt.Errorf("cannot calc restore plan: %w", err)
} else if len(infos) == 0 {
return fmt.Errorf("no backup files available")
}
// Disable hydrated reads during time travel - hydrated file is at latest state
if f.hydrator != nil && f.hydrator.Complete() {
f.hydrator.Disable()
f.logger.Debug("hydration disabled for time travel", "target", timestamp)
}
return f.rebuildIndex(ctx, infos, ×tamp)
}
// ResetTime rebuilds the page index to the latest available state.
func (f *VFSFile) ResetTime(ctx context.Context) error {
infos, err := CalcRestorePlan(ctx, f.client, 0, time.Time{}, f.logger)
if err != nil {
return fmt.Errorf("cannot calc restore plan: %w", err)View on GitHub (pinned to 4ed7a308f6)
Solutions
- Choose a timestamp within the replica's covered range (after the earliest available snapshot)
- Verify LTX file metadata integrity with litestream ltx and re-replicate if corrupt
- Check replica storage connectivity/permissions so listing succeeds
- Retry on transient listing errors
Defensive patterns
Strategy: validation
Validate before calling
infos, _ := client.LTXInfos(ctx)
minT := earliestTimestamp(infos)
if targetTime.Before(minT) { return fmt.Errorf("target %v predates earliest snapshot %v", targetTime, minT) } Type guard
func targetCovered(t time.Time, minT time.Time) bool { return !t.Before(minT) } Try / catch
if err := file.SetTargetTime(ctx, t); err != nil {
if strings.Contains(err.Error(), "cannot calc restore plan") {
return fmt.Errorf("no LTX coverage for %v: %w", t, err)
}
return err
} Prevention
- Discover the replica's earliest snapshot time before time-traveling
- Validate LTX metadata integrity periodically
- Handle retention: don't assume old timestamps are restorable
When it happens
Trigger: CalcRestorePlan returns an error for a given timestamp — LTX listing fails, LTX file metadata is inconsistent/corrupt, timestamps in infos overlap or are malformed, or the replica client errors during listing.
Common situations: Time-travel target predates the earliest snapshot or sits in a gap caused by deleted/compacted LTX files; corrupt LTX metadata in the bucket; replica listing failures (permissions, network).
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- no backup files available
- invalid replica, checksum mismatch
- ltx file corrupted
- ltx file missing
- invalid level: must be 0-%d or "all"
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/671df25bd69a3757.
Report an issue: GitHub.