benbjohnson/litestream · error
fetch ltx files: %w
Error message
fetch ltx files: %w
What it means
EnforceSnapshotRetention could not open the LTX file iterator for the snapshot level (SnapshotLevel) because c.client.LTXFiles returned an error; the retention sweep aborts with 'fetch ltx files: <err>'. No snapshot files are evaluated or deleted when this fires — it's a listing failure at the storage layer, before any cleanup happens.
Source
Thrown at compactor.go:244
}
if err := itr.Close(); err != nil {
return fmt.Errorf("close iterator: %w", err)
}
return nil
}
// EnforceSnapshotRetention enforces retention of snapshot level files by timestamp.
// Files older than the retention duration are deleted (except the newest is always kept).
// Returns the minimum snapshot TXID still retained (useful for cascading retention to lower levels).
func (c *Compactor) EnforceSnapshotRetention(ctx context.Context, retention time.Duration) (ltx.TXID, error) {
timestamp := time.Now().Add(-retention)
c.logger.Debug("enforcing snapshot retention", "timestamp", timestamp)
itr, err := c.client.LTXFiles(ctx, SnapshotLevel, 0, false)
if err != nil {
return 0, fmt.Errorf("fetch ltx files: %w", err)
}
defer itr.Close()
var deleted []*ltx.FileInfo
var lastInfo *ltx.FileInfo
var minSnapshotTXID ltx.TXID
for itr.Next() {
info := itr.Item()
lastInfo = info
if info.CreatedAt.Before(timestamp) {
deleted = append(deleted, info)
continue
}
if minSnapshotTXID == 0 || info.MaxTXID < minSnapshotTXID {
minSnapshotTXID = info.MaxTXIDView on GitHub (pinned to 4ed7a308f6)
Solutions
- Inspect the wrapped error — auth vs network vs missing bucket/prefix
- Verify replica storage config (endpoint, bucket, prefix, credentials) with `litestream ltx -level <n>` or a direct storage listing
- Re-authenticate / fix IAM permissions so listing snapshot-level files is allowed
- Check network/VPN to the storage endpoint; retry after outage
- Ensure the local replica directory wasn't deleted; run `litestream reset <db>` if local LTX state is corrupt
Defensive patterns
Strategy: retry
Validate before calling
// pre-flight listing before relying on retention:
itr, err := client.LTXFiles(ctx, litestream.SnapshotLevel, 0, false)
if err != nil { log.Fatalf("storage listing unavailable: %v", err) }
itr.Close() Try / catch
if err := compactor.EnforceSnapshotRetention(ctx, retention); err != nil {
if strings.Contains(err.Error(), "fetch ltx files") {
// check credentials/bucket, then retry with backoff
}
} Prevention
- Validate replica credentials and bucket/prefix in config before enabling retention
- Grant the storage principal list permissions (e.g. s3:ListBucket)
- Alert on storage outages so retention failures are noticed
- Don't delete local replica directories out-of-band; use litestream reset instead
When it happens
Trigger: Called by monitorSnapshots when enforcing snapshot retention; the storage client fails to list snapshot-level files — missing bucket/prefix, revoked credentials, network failure, context canceled, or the ReplicaClient not supporting listing for that level.
Common situations: S3 credentials expired or IAM policy lacking ListObjectsV2; bucket/prefix misconfigured in the replica config; storage outage; local file replica directory removed out-of-band; retention monitor running against a replica client that can't reach the remote.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/15aac93623140581.
Report an issue: GitHub.