benbjohnson/litestream · error

list generations: %w

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.

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)

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.