benbjohnson/litestream · error

list snapshots for generation %s: %w

Error message

list snapshots for generation %s: %w

What it means

After listing generations, RestoreV3 iterates them and calls client.SnapshotsV3(ctx, gen) to collect snapshots per generation. A failure listing snapshots inside any single generation is wrapped as 'list snapshots for generation %s: %w' with the generation name included, pinpointing which generation's listing failed.

Source

Thrown at replica.go:1101

	} 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
	}

	// Sort all snapshots by CreatedAt for timestamp-based selection.
	sortSnapshotsV3ByCreatedAt(allSnapshots)

	// Find best snapshot across all generations (latest, or before timestamp if specified).
	snapshot := findBestSnapshotV3(allSnapshots, opt.Timestamp)
	if snapshot == nil {
		return ErrNoSnapshots
	}

	r.Logger().Debug("selected v0.3.x snapshot",
		"generation", snapshot.Generation,

View on GitHub (pinned to 4ed7a308f6)

Solutions

  1. Read the wrapped cause and generation name to identify the failing generation and backend error
  2. Check storage permissions on that generation's prefix and repair or remove the corrupt generation from the replica
  3. Retry the restore; the failure may be transient throttling
  4. If one generation is unrecoverable but others are healthy, this listing error still blocks restore — fix or delete the bad generation in storage
Defensive patterns

Strategy: retry

Validate before calling

// preflight: ensure every generation's snapshots are listable
for _, gen := range generations {
    if _, err := client.SnapshotsV3(ctx, gen); err != nil {
        return fmt.Errorf("generation %s not listable: %w", gen, err)
    }
}

Try / catch

if err := replica.Restore(ctx, opt); err != nil {
    if strings.Contains(err.Error(), "list snapshots for generation") {
        var genName string
        fmt.Sscanf(err.Error(), "list snapshots for generation %s", &genName)
        log.Printf("fix listing for generation %q, cause=%v", genName, errors.Unwrap(err))
        return err
    }
    return err
}

Prevention

When it happens

Trigger: Calling Replica.Restore when listing snapshot objects for one generation fails — typically a partial/corrupt generation directory in the storage backend, a storage API error (throttle, permission on a prefix), or a transient network failure mid-iteration over multiple generations.

Common situations: Backends with per-prefix permissions where one generation's prefix is inaccessible; S3 throttling while listing many generations; interrupted replication leaving a malformed generation that the backend cannot list; snapshot listing for a generation deleted between the GenerationsV3 and SnapshotsV3 calls.

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