benbjohnson/litestream · error

list generations

Error message

list generations: %w

What it means

RestoreV3 enumerates backup generations via client.GenerationsV3(ctx); if that remote listing fails the underlying error is wrapped as 'list generations: %w'. It is a transport/storage error while talking to the replica client backend (S3, file system, etc.), not an options problem. An empty (but successful) listing instead yields ErrNoSnapshots.

Solutions

  1. Inspect the wrapped cause (%w) with errors.Unwrap/%v to see the storage error (auth, DNS, 4xx/5xx) and fix that backend issue
  2. Verify replica client config: bucket, endpoint, region, credentials, network reachability
  3. Retry the restore; generation listing is read-only and safe to repeat
  4. Run litestream ltx or list the bucket manually to confirm generations are visible

Example fix

// before
err := replica.Restore(ctx, opt) // opaque 'list generations: ...'
// after
if err := replica.Restore(ctx, opt); err != nil {
    var ctxErr context.Error
    log.Printf("restore failed, cause=%v", errors.Unwrap(err)) // surface backend error
    _ = ctxErr
    return err
}
Defensive patterns

Strategy: retry

Validate before calling

// preflight: verify the backend is reachable and listable before restore
if _, err := client.GenerationsV3(ctx); err != nil {
    return fmt.Errorf("replica backend unreachable: %w", err)
}

Try / catch

if err := replica.Restore(ctx, opt); err != nil {
    var ne net.Error
    if errors.As(err, &ne) || strings.Contains(err.Error(), "list generations") {
        return retryWithBackoff(ctx, 3, func() error { return replica.Restore(ctx, opt) })
    }
    return err
}

Prevention

When it happens

Trigger: Calling Replica.Restore against a v0.3.x replica when the storage backend is unreachable, credentials are wrong, the bucket/container does not exist, or the backend returned a transient error while listing generation directories.

Common situations: Offline or misconfigured network during disaster recovery; expired S3 credentials or wrong region; pointing the client at the wrong bucket after a config change; S3 outage or throttling during list requests.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at replica.go:1090

	// Validate options.
	if opt.OutputPath == "" {
		return fmt.Errorf("output path required")
	} else if opt.IntegrityCheck != IntegrityCheckNone && opt.IntegrityCheck != IntegrityCheckQuick && opt.IntegrityCheck != IntegrityCheckFull {
		return fmt.Errorf("unsupported integrity check mode: %d", opt.IntegrityCheck)
	}

	// Ensure output path does not already exist.
	if _, err := os.Stat(opt.OutputPath); err == nil {
		return fmt.Errorf("cannot restore, output path already exists: %s", opt.OutputPath)
	} else if !os.IsNotExist(err) {
		return err
	}

	// Find all generations.
	generations, err := client.GenerationsV3(ctx)
	if err != nil {
		return fmt.Errorf("list generations: %w", err)
	}
	if len(generations) == 0 {
		return ErrNoSnapshots
	}

	// Collect all snapshots across all generations.
	var allSnapshots []SnapshotInfoV3
	for _, gen := range generations {
		snapshots, err := client.SnapshotsV3(ctx, gen)
		if err != nil {
			return fmt.Errorf("list snapshots for generation %s: %w", gen, err)
		}
		allSnapshots = append(allSnapshots, snapshots...)
	}
	if len(allSnapshots) == 0 {
		return ErrNoSnapshots
	}

View on GitHub (pinned to 4ed7a308f6)