{"record":{"id":"46691e9f2589e6dd","repo":"benbjohnson/litestream","slug":"remove-ltx-files-w","errorCode":null,"errorMessage":"remove ltx files: %w","messagePattern":"remove ltx files: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compactor.go","lineNumber":273,"sourceCode":"\n\t\tif info.CreatedAt.Before(timestamp) {\n\t\t\tdeleted = append(deleted, info)\n\t\t\tcontinue\n\t\t}\n\n\t\tif minSnapshotTXID == 0 || info.MaxTXID < minSnapshotTXID {\n\t\t\tminSnapshotTXID = info.MaxTXID\n\t\t}\n\t}\n\n\tif len(deleted) > 0 && deleted[len(deleted)-1] == lastInfo {\n\t\tdeleted = deleted[:len(deleted)-1]\n\t}\n\n\tif !c.RetentionEnabled {\n\t\tc.logger.Debug(\"skipping remote deletion (retention disabled)\", \"level\", SnapshotLevel, \"count\", len(deleted))\n\t} else if err := c.client.DeleteLTXFiles(ctx, deleted); err != nil {\n\t\treturn 0, fmt.Errorf(\"remove ltx files: %w\", err)\n\t}\n\n\tif c.LocalFileDeleter != nil {\n\t\tfor _, info := range deleted {\n\t\t\tc.logger.Debug(\"deleting local ltx file\",\n\t\t\t\t\"level\", SnapshotLevel,\n\t\t\t\t\"minTXID\", info.MinTXID,\n\t\t\t\t\"maxTXID\", info.MaxTXID)\n\t\t\tif err := c.LocalFileDeleter(SnapshotLevel, info.MinTXID, info.MaxTXID); err != nil {\n\t\t\t\tc.logger.Error(\"failed to remove local ltx file\", \"error\", err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn minSnapshotTXID, nil\n}\n\n// EnforceRetentionByTXID deletes files at the given level with maxTXID below the target.","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/compactor.go#L255-L291","documentation":"EnforceSnapshotRetention removes expired snapshot-level LTX files from remote storage. When the underlying replica client's DeleteLTXFiles call fails, the error is wrapped with 'remove ltx files: %w'. This is a remote storage deletion failure during snapshot retention enforcement, not a local file operation.","triggerScenarios":"Calling EnforceSnapshotRetention (directly or via monitorSnapshots) when RetentionEnabled is true and client.DeleteLTXFiles(ctx, deleted) returns an error — e.g. network outage, storage backend permissions revoked, expired credentials, or S3-compatible API 5xx during the batch delete.","commonSituations":"Expired or rotated cloud credentials mid-run; storage bucket policies denying s3:DeleteMultiObjectDelete; transient network partition to the replica storage; provider rate limiting on batch deletes.","solutions":["Verify storage credentials and IAM permissions allow batch deletion of objects in the replica path","Retry the retention enforcement — the next monitor cycle re-computes the expired set","Check the wrapped error for provider-specific causes (throttling, access denied) and address that backend issue","Confirm the replica storage endpoint is reachable and not in a degraded state"],"exampleFix":"// before: failing silently or ignoring\nif err := c.EnforceSnapshotRetention(ctx); err != nil {\n    c.logger.Debug(\"retention failed\", \"err\", err)\n}\n// after: surface and retry with backoff\nif err := c.EnforceSnapshotRetention(ctx); err != nil {\n    return fmt.Errorf(\"snapshot retention: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"// Go: verify storage access before enabling retention\niter, err := client.LTXFiles(ctx, ltx.SnapshotLevel, 0, false)\nif err != nil { log.Fatal(err) }\niter.Close()","typeGuard":null,"tryCatchPattern":"if err := c.EnforceSnapshotRetention(ctx); err != nil {\n    var netErr net.Error\n    if errors.As(err, &netErr) { /* retry with backoff */ }\n    return fmt.Errorf(\"snapshot retention: %w\", err)\n}","preventionTips":["Grant delete permissions to storage credentials","Monitor credential expiry and rotate before failure","Alert on wrapped 'remove ltx files' errors from retention loops"],"tags":["storage","deletion","retention","network"],"backgroundTag":"file-delete-failed","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}