benbjohnson/litestream · error
failed to list objects in GCS bucket %s (path: %s): %w
Error message
failed to list objects in GCS bucket %s (path: %s): %w
What it means
DeleteAll() failed while iterating objects under the configured path prefix in the GCS bucket. The underlying storage.Query iterator returned an error other than iterator.Done (e.g. permission denied, bucket missing, transient API failure), wrapped with the bucket and path. Deletion aborts at the first listing error, leaving some objects potentially undeleted.
Source
Thrown at gs/replica_client.go:107
c.bkt = c.client.Bucket(c.Bucket)
return nil
}
// DeleteAll deletes all LTX files.
func (c *ReplicaClient) DeleteAll(ctx context.Context) error {
if err := c.Init(ctx); err != nil {
return err
}
// Iterate over every object and delete it.
internal.OperationTotalCounterVec.WithLabelValues(ReplicaClientType, "LIST").Inc()
for it := c.bkt.Objects(ctx, &storage.Query{Prefix: c.Path + "/"}); ; {
attrs, err := it.Next()
if errors.Is(err, iterator.Done) {
break
} else if err != nil {
return fmt.Errorf("failed to list objects in GCS bucket %s (path: %s): %w", c.Bucket, c.Path, err)
}
if err := c.bkt.Object(attrs.Name).Delete(ctx); isNotExists(err) {
continue
} else if err != nil {
return fmt.Errorf("gs: cannot delete object %q: %w", attrs.Name, err)
}
internal.OperationTotalCounterVec.WithLabelValues(ReplicaClientType, "DELETE").Inc()
}
// log.Printf("%s(%s): retainer: deleting", r.db.Path(), r.Name())
return nil
}
// LTXFiles returns an iterator over all available LTX files for a level.
// GCS always uses accurate timestamps from metadata since they're included in LIST operations at zero cost.
// The useMetadata parameter is ignored.View on GitHub (pinned to 4ed7a308f6)
Solutions
- Check the wrapped cause for the GCS API error (403 vs 404 vs 5xx) and address that specifically
- Grant the service account roles/storage.objectAdmin (or objectViewer+objectCreator+objectDeleter) on the bucket
- Verify the bucket name in the config with `gsutil ls gs://<bucket>` using the same credentials
- Retry — transient 5xx/rate-limit errors are often temporary; consider backoff
- Confirm bucket/path prefix matches what litestream actually wrote
Example fix
# before: permission denied listing # after — grant access gsutil iam ch serviceAccount:sa@project.iam.gserviceaccount.com:roles/storage.objectAdmin gs://my-bucket
Defensive patterns
Strategy: try-catch
Validate before calling
it := bkt.Objects(ctx, &storage.Query{Prefix: path + "/"})
if _, err := it.Next(); err != nil && err != iterator.Done {
// list permission or bucket problem detected up front
} Try / catch
if err := rc.DeleteAll(ctx); err != nil {
if strings.Contains(err.Error(), "403") {
// grant objectAdmin IAM role
}
return err
} Prevention
- Grant roles/storage.objectAdmin, not objectViewer, for replication destinations
- Validate bucket names in config with a startup check
- Monitor GCS 429/5xx rates; add backoff around bulk deletes
When it happens
Trigger: Calling DeleteAll() when the bucket name is wrong/nonexistent, the credentials lack storage.objects.list permission on the bucket, the GCS API returns a transient 5xx, or the context is canceled mid-iteration.
Common situations: Service account missing roles/storage.objectAdmin; typo'd bucket in litestream.yml; bucket deleted externally while litestream runs; GCS outage or rate limiting during a full-replica delete.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- gs: cannot delete object %q: %w
- failed to create GCS client (bucket: %s): %w
- gs: cannot delete ltx file %q: %w
- abs: cannot delete ltx file %q: %w
- abs: cannot list blobs: %w
AI-assisted analysis of benbjohnson/litestream@4ed7a308f6 (2026-09-06).
Data as JSON: /api/errors/53f4212dc40b6ef4.
Report an issue: GitHub.