benbjohnson/litestream · error

find LTX snapshot: %w

Error message

find LTX snapshot: %w

What it means

Wraps an error from findBestLTXSnapshotForTimestamp during timestamp-based restore format selection. Listing LTX snapshot-level files (level-sorted, filtered by CreatedAt < timestamp) failed, so Litestream cannot compare LTX against the v0.3.x candidate.

Source

Thrown at replica.go:1434

	}

	// If no LTX backups exist, use v0.3.x.
	if ltxUpdatedAt.IsZero() {
		r.Logger().Debug("using v0.3.x restore (no LTX backups)")
		return true, nil
	}

	// Both formats have backups - compare based on timestamp or latest.
	if !timestamp.IsZero() {
		// With timestamp: use format with best snapshot before timestamp.
		v3Snapshot, err := r.findBestV3SnapshotForTimestamp(ctx, client, timestamp)
		if err != nil {
			return false, fmt.Errorf("find v0.3.x snapshot: %w", err)
		}

		ltxSnapshot, err := r.findBestLTXSnapshotForTimestamp(ctx, timestamp)
		if err != nil {
			return false, fmt.Errorf("find LTX snapshot: %w", err)
		}

		if v3Snapshot != nil && (ltxSnapshot == nil || v3Snapshot.CreatedAt.After(ltxSnapshot.CreatedAt)) {
			r.Logger().Debug("using v0.3.x restore (better snapshot for timestamp)",
				"v3_snapshot", v3Snapshot.CreatedAt,
				"ltx_snapshot", ltxSnapshot)
			return true, nil
		}
	} else {
		// Without timestamp: use format with most recent backup.
		if v3UpdatedAt.After(ltxUpdatedAt) {
			r.Logger().Debug("using v0.3.x restore (more recent backup)",
				"v3_updated_at", v3UpdatedAt,
				"ltx_updated_at", ltxUpdatedAt)
			return true, nil
		}
	}

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Inspect the wrapped cause; verify read permissions on snapshot-level LTX prefixes.
  2. Retry the restore if transient.
  3. Check that lifecycle/retention rules are not deleting snapshot files before your PITR window (disable retention only when a cloud lifecycle policy owns cleanup).
  4. Restore latest without -timestamp to skip the snapshot filter.

Example fix

// before
ltxSnapshot, err := r.findBestLTXSnapshotForTimestamp(ctx, timestamp)
// after
// ensure snapshot LTX files exist and are readable:
// $ litestream ltx -level 4 <replica>   // inspect levels
// then retry the timestamped restore
ltxSnapshot, err := r.findBestLTXSnapshotForTimestamp(ctx, timestamp)
Defensive patterns

Strategy: validation

Validate before calling

// Go: check snapshot-level files exist before a timestamped restore
infos, err := FindLTXFiles(ctx, client, SnapshotLevel, true, nil)
if err != nil || len(infos) == 0 {
    return fmt.Errorf("no restorable LTX snapshots found")
}

Try / catch

if err != nil {
    if strings.Contains(err.Error(), "find LTX snapshot") {
        // verify snapshot prefixes readable; retry or restore latest
    }
    return err
}

Prevention

When it happens

Trigger: Restore -timestamp with both formats present and FindLTXFiles on SnapshotLevel fails: storage backend error while listing snapshot LTX files, or the filter callback's enumeration hitting a corrupt/unreadable object.

Common situations: Lifecycle policies deleting snapshot LTX files mid-restore; IAM missing read permission on snapshot prefixes; transient object-store 5xx errors.

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/e8720c287b0e2343. Report an issue: GitHub.