benbjohnson/litestream · error

no backups found

Error message

no backups found

What it means

When RestoreOptions.Timestamp is set, CalcRestoreTarget requires known time bounds (createdAt/updatedAt) to validate the requested timestamp. If both bounds are zero — meaning no backups of any format were found in the replica — restore target computation fails with 'no backups found'. It indicates the replica has nothing restorable, not that the timestamp is out of range.

Solutions

  1. Verify the replica actually has backups: run `litestream ltx` / list the storage location.
  2. Check the config's bucket/prefix/replica path points to the location containing backups.
  3. Run a sync (`litestream replicate`) to create an initial backup before restoring.
  4. If backups were deleted by retention/lifecycle policies, restore from a different replica or snapshot.
Defensive patterns

Strategy: validation

Validate before calling

// check the replica has backups before a timestamped restore
infos, err := client.ListLTXFiles(ctx, 0)
if err != nil || len(infos) == 0 {
    return fmt.Errorf("replica %s has no backups", replicaName)
}

Try / catch

err := replica.Restore(ctx, opt)
if err != nil && errors.Is(err, errors.New("no backups found")) || strings.Contains(err.Error(), "no backups found") {
    // fall back to another replica or create a fresh backup first
}

Prevention

When it happens

Trigger: CalcRestoreTarget (and thus restore with -timestamp) is called on a replica whose storage contains no LTX files and no legacy backups, so TimeBounds/TimeBoundsV3 returned zero timestamps.

Common situations: Typo in config bucket/prefix pointing at an empty location; a replica that never completed its first sync; storage cleaned by lifecycle policies; using the wrong replica name in restore command.

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

Appendix: source

Thrown at replica.go:587

	// Also check v0.3.x time bounds if client supports it.
	if client, ok := r.Client.(ReplicaClientV3); ok {
		v3CreatedAt, v3UpdatedAt, err := r.TimeBoundsV3(ctx, client)
		if err != nil {
			return time.Time{}, fmt.Errorf("v0.3.x time bounds: %w", err)
		}
		// Extend time bounds to include v0.3.x backups.
		if !v3CreatedAt.IsZero() && (createdAt.IsZero() || v3CreatedAt.Before(createdAt)) {
			createdAt = v3CreatedAt
		}
		if !v3UpdatedAt.IsZero() && (updatedAt.IsZero() || v3UpdatedAt.After(updatedAt)) {
			updatedAt = v3UpdatedAt
		}
	}

	// Skip if it does not contain timestamp.
	if !opt.Timestamp.IsZero() {
		if createdAt.IsZero() && updatedAt.IsZero() {
			return time.Time{}, fmt.Errorf("no backups found")
		}
		if opt.Timestamp.Before(createdAt) || opt.Timestamp.After(updatedAt) {
			return time.Time{}, fmt.Errorf("timestamp does not exist")
		}
	}

	return updatedAt, nil
}

// Replica restores the database from a replica based on the options given.
// This method will restore into opt.OutputPath, if specified, or into the
// DB's original database path. It can optionally restore from a specific
// replica or it will automatically choose the best one. Finally,
// a timestamp can be specified to restore the database to a specific
// point-in-time.
//
// When the replica contains both v0.3.x and LTX format backups, this method
// compares snapshots from both formats and uses whichever has the better backup:

View on GitHub (pinned to 4ed7a308f6)