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, &timestamp)
}

// 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

  1. Choose a timestamp within the replica's covered range (after the earliest available snapshot)
  2. Verify LTX file metadata integrity with litestream ltx and re-replicate if corrupt
  3. Check replica storage connectivity/permissions so listing succeeds
  4. 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

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


AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06). Data as JSON: /api/errors/671df25bd69a3757. Report an issue: GitHub.