{"record":{"id":"c96594a1c91ae96f","repo":"benbjohnson/litestream","slug":"remove-ltx-files-w-c96594","errorCode":null,"errorMessage":"remove ltx files: %w","messagePattern":"remove ltx files: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"db.go","lineNumber":3001,"sourceCode":"\t// Use the last deleted snapshot's MaxTXID, rather than the first retained\n\t// snapshot's MaxTXID, to preserve lower-level files in an in-flight restore\n\t// plan. TestStore_EnforceSnapshotRetention_RetainsInFlightRestorePlanFiles\n\t// guards this conservative floor.\n\tfor i, info := range snapshots {\n\t\tif slices.Contains(deleted, info) {\n\t\t\tcontinue\n\t\t}\n\t\tif i > 0 {\n\t\t\tminSnapshotTXID = snapshots[i-1].MaxTXID\n\t\t}\n\t\tbreak\n\t}\n\n\t// Remove files marked for deletion from remote storage (unless retention disabled).\n\tif !db.RetentionEnabled {\n\t\tdb.Logger.Debug(\"skipping remote deletion (retention disabled)\", \"level\", SnapshotLevel, \"count\", len(deleted))\n\t} else if err := db.Replica.Client.DeleteLTXFiles(ctx, deleted); err != nil {\n\t\treturn 0, fmt.Errorf(\"remove ltx files: %w\", err)\n\t}\n\n\t// Always clean up local files.\n\tfor _, info := range deleted {\n\t\tlocalPath := db.LTXPath(SnapshotLevel, info.MinTXID, info.MaxTXID)\n\t\tdb.Logger.Debug(\"deleting local ltx file\", \"level\", SnapshotLevel, \"minTXID\", info.MinTXID, \"maxTXID\", info.MaxTXID, \"path\", localPath)\n\n\t\tif err := os.Remove(localPath); err != nil && !os.IsNotExist(err) {\n\t\t\tdb.Logger.Error(\"failed to remove local ltx file\", \"path\", localPath, \"error\", err)\n\t\t}\n\t}\n\n\treturn minSnapshotTXID, nil\n}\n\n// EnforceL0RetentionByTime retains L0 files until they have been compacted into\n// L1 and have existed for at least L0Retention.\nfunc (db *DB) EnforceL0RetentionByTime(ctx context.Context) error {","sourceCodeStart":2983,"sourceCodeEnd":3019,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/db.go#L2983-L3019","documentation":"Wraps a failure from Replica.Client.DeleteLTXFiles when removing snapshot-level LTX files marked for deletion during EnforceSnapshotRetention. The remote deletion failed; local cleanup still proceeds and the operation can be retried safely since deletions are idempotent.","triggerScenarios":"EnforceSnapshotRetention with RetentionEnabled=true calling DeleteLTXFiles on expired snapshots while the backend rejects deletes: permission denied on bucket, object-lock/immutability policies, or a transient network error mid-batch.","commonSituations":"S3 bucket with Object Lock or Glacier storage class blocking deletes; IAM policy lacking s3:DeleteObject; GCS retention policy; network drop during deletion.","solutions":["Grant delete permission on the replica bucket/prefix to the credentials in use.","Check for object lock, retention policy, or lifecycle rules blocking deletes.","Inspect the wrapped error for the specific object keys and delete/verify manually.","Retry; deletion is idempotent and partial completions are harmless.","If a storage lifecycle policy handles cleanup, set retention disabled to skip remote deletion."],"exampleFix":"// before\nif err := db.Replica.Client.DeleteLTXFiles(ctx, deleted); err != nil { return 0, fmt.Errorf(\"remove ltx files: %w\", err) }\n// after (caller retry)\nerr := db.Replica.Client.DeleteLTXFiles(ctx, deleted)\nif err != nil && isTransient(err) { err = db.Replica.Client.DeleteLTXFiles(ctx, deleted) }\nif err != nil { return 0, fmt.Errorf(\"remove ltx files: %w\", err) }","handlingStrategy":"try-catch","validationCode":"// ensure credentials allow delete before enabling retention\n// aws iam simulate-principal-policy --action-names s3:DeleteObject","typeGuard":null,"tryCatchPattern":"if err := db.Replica.Client.DeleteLTXFiles(ctx, deleted); err != nil {\n    if isTransient(err) { scheduleRetry() } else { logAndAlert(err) }\n}","preventionTips":["Grant delete permissions on the replica prefix.","Avoid object lock/retention policies on litestream buckets.","Keep retention enabled or rely on a verified lifecycle policy."],"tags":["storage","deletion","retention","permissions"],"backgroundTag":"file-write-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"}