benbjohnson/litestream · error

no matching backup files available

Error message

no matching backup files available

What it means

With --dry-run, restore computes a plan via c.dryRunPlan; if the planner reports litestream.ErrTxNotAvailable, meaning no backup files in the replica match the requested timestamp/TXID constraints, the command converts it into the friendlier message "no matching backup files available". Nothing was restored; the replica simply lacks a usable snapshot/transaction for the request.

Source

Thrown at cmd/litestream/restore.go:121

		} else if err != nil {
			return err
		}
	} else {
		if *configPath == "" {
			*configPath = DefaultConfigPath()
		}
		if r, err = c.loadFromConfig(ctx, fs.Arg(0), *configPath, !*noExpandEnv, *ifDBNotExists, &opt); errors.Is(err, errSkipDBExists) {
			slog.Info("database already exists, skipping")
			return nil
		} else if err != nil {
			return err
		}
	}

	if *dryRun {
		plan, err := c.dryRunPlan(ctx, fs.Arg(0), r, opt)
		if errors.Is(err, litestream.ErrTxNotAvailable) {
			return fmt.Errorf("no matching backup files available")
		} else if err != nil {
			return err
		}
		if *jsonOutput {
			output, err := json.MarshalIndent(plan, "", "  ")
			if err != nil {
				return fmt.Errorf("failed to format response: %w", err)
			}
			fmt.Println(string(output))
			return nil
		}
		c.printDryRunPlan(plan)
		return nil
	}

	if !opt.Follow {
		if err := c.prepareOutputPath(opt.OutputPath, *force); err != nil {
			return err

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. List what is actually available (e.g. `litestream ltx -level all` or a dry-run without tight constraints) to see the replica's coverage
  2. Omit or widen -timestamp/-txid to restore the latest available state instead
  3. Verify the replica URL/bucket/prefix points at the right replication target
  4. Check retention settings — the needed snapshot may have been deleted; restore from another replica or accept a newer point-in-time

Example fix

// before (timestamp before any backup existed)
litestream restore --dry-run -timestamp 2020-01-01T00:00:00Z s3://bucket/prefix
// after (latest available)
litestream restore --dry-run s3://bucket/prefix
Defensive patterns

Strategy: fallback

Validate before calling

// Probe availability before requesting a specific point in time
plan, err := dryRunPlan(ctx, url, nil, optNoConstraints)
if errors.Is(err, litestream.ErrTxNotAvailable) {
    return fmt.Errorf("replica %s has no backups at all", url)
}

Try / catch

plan, err := dryRunPlan(ctx, arg, r, opt)
if errors.Is(err, litestream.ErrTxNotAvailable) {
    // retry without -timestamp/-txid to get latest available
    opt.Timestamp, opt.TxID = time.Time{}, zeroTxID
    plan, err = dryRunPlan(ctx, arg, r, opt)
}

Prevention

When it happens

Trigger: `litestream restore --dry-run ...` where the target replica has no snapshots, the requested -timestamp predates the earliest backup or exceeds retention, or a -txid is given that doesn't exist in the replica.

Common situations: Retention window expired so old snapshots were deleted from S3; wrong bucket/prefix (empty or unrelated replica); asking for a timestamp from before replication was first set up; replica URL typo pointing at an empty prefix.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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