benbjohnson/litestream · error

find v0.3.x snapshot

Error message

find v0.3.x snapshot: %w

What it means

Wraps an error from findBestV3SnapshotForTimestamp when comparing v0.3.x and LTX snapshots against a requested restore timestamp. Litestream could not enumerate v0.3.x snapshots, so it cannot decide which format holds the best snapshot before the timestamp.

Solutions

  1. Resolve the underlying SnapshotsV3 failure (credentials, network, generation presence).
  2. Retry the timestamp restore; throttled listings usually succeed on retry.
  3. Restore without -timestamp (latest) to bypass the timestamp comparison path.
  4. Reduce generation count/fragmentation by re-replicating into a clean generation.

Example fix

// before
$ litestream restore -timestamp 2024-01-01T00:00:00Z db
// error: find v0.3.x snapshot: ...
// after
// fix credentials, then retry; or restore latest:
$ litestream restore db
Defensive patterns

Strategy: retry

Try / catch

if err := restoreWithTimestamp(ts); err != nil {
    if strings.Contains(err.Error(), "find v0.3.x snapshot") {
        // fall back to latest restore or fix backend listing then retry
        return retryOrFallback(err)
    }
    return err
}

Prevention

When it happens

Trigger: Restore with a -timestamp option where both v0.3.x and LTX backups exist and SnapshotsV3 fails for any generation (same cause family as error 460).

Common situations: Timestamp-based PITR against a migrated replica; stale credentials; backend throttling during listing of many generations.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


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

Appendix: source

Thrown at replica.go:1429

	}

	// If no v0.3.x backups exist, use LTX.
	if v3UpdatedAt.IsZero() {
		return false, nil
	}

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

View on GitHub (pinned to 4ed7a308f6)