{"record":{"id":"b28b1b796c6dd678","repo":"benbjohnson/litestream","slug":"todo-ltx-re-implement-after-multi-level-compacti","errorCode":null,"errorMessage":"TODO(ltx): Re-implement after multi-level compaction","messagePattern":"TODO\\(ltx\\): Re-implement after multi-level compaction","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"replica.go","lineNumber":319,"sourceCode":"// Pos returns the current replicated position.\n// Returns a zero value if the current position cannot be determined.\nfunc (r *Replica) Pos() ltx.Pos {\n\tr.mu.RLock()\n\tdefer r.mu.RUnlock()\n\treturn r.pos\n}\n\n// SetPos sets the current replicated position.\nfunc (r *Replica) SetPos(pos ltx.Pos) {\n\tr.mu.Lock()\n\tdefer r.mu.Unlock()\n\tr.pos = pos\n}\n\n// EnforceRetention forces a new snapshot once the retention interval has passed.\n// Older snapshots and WAL files are then removed.\nfunc (r *Replica) EnforceRetention(ctx context.Context) (err error) {\n\tpanic(\"TODO(ltx): Re-implement after multi-level compaction\")\n\n\t/*\n\t\t// Obtain list of snapshots that are within the retention period.\n\t\tsnapshots, err := r.Snapshots(ctx)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"snapshots: %w\", err)\n\t\t}\n\t\tretained := FilterSnapshotsAfter(snapshots, time.Now().Add(-r.Retention))\n\n\t\t// If no retained snapshots exist, create a new snapshot.\n\t\tif len(retained) == 0 {\n\t\t\tsnapshot, err := r.Snapshot(ctx)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"snapshot: %w\", err)\n\t\t\t}\n\t\t\tretained = append(retained, snapshot)\n\t\t}\n","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/replica.go#L301-L337","documentation":"Replica.EnforceRetention is currently a stub: multi-level compaction work in the LTX rewrite left retention enforcement unimplemented, so the method panics with a TODO marker. The original retention logic (listing/removing old snapshots and WAL files) is commented out. Any caller invoking it on this version of the code will crash.","triggerScenarios":"Any call to (*litestream.Replica).EnforceRetention(ctx) on this source revision — e.g. external code that used the library API to enforce retention, or store loops still wired to it — hits the panic unconditionally.","commonSituations":"Upgrading to the LTX-era version of litestream while code (or a fork/monitor) still calls EnforceRetention directly; expecting retention to run automatically and instead getting a crash; depending on the removed retention behavior after a version change.","solutions":["Stop calling EnforceRetention until the TODO is implemented; manage retention on the replica backend (e.g. S3 lifecycle rules) instead","Pin to the last version before the LTX rewrite if you need programmatic EnforceRetention","Check store.go / current config options for replacement retention settings; upgrade litestream if a later release re-implements retention"],"exampleFix":"// before\nif err := replica.EnforceRetention(ctx); err != nil { ... } // panics\n// after: rely on storage lifecycle policy instead\n// e.g. S3 bucket lifecycle rule: expire *.ltx older than 24h","handlingStrategy":"validation","validationCode":"// Go: guard the call site against the stub implementation\n// TODO was flagged in source: replica.go EnforceRetention panics on this version.\nif retentionEnforcedExplicitly {\n    return errors.New(\"EnforceRetention is unimplemented in this litestream version; use storage lifecycle rules\")\n}","typeGuard":null,"tryCatchPattern":"// panic-based stub: recover defensively if you must call it\nfunc safeEnforceRetention(ctx context.Context, r *litestream.Replica) (err error) {\n    defer func() { if p := recover(); p != nil { err = fmt.Errorf(\"EnforceRetention unavailable: %v\", p) } }()\n    return r.EnforceRetention(ctx)\n}","preventionTips":["Do not call EnforceRetention directly in this version; rely on storage-level retention (S3 lifecycle, etc.)","Pin litestream versions and read release notes for the LTX rewrite's API removals","Check the source for panic(\"TODO\") stubs before depending on a method","If retention is required, upgrade to a release that re-implements it or manage it externally"],"tags":["retention","unimplemented","panic","api-change"],"backgroundTag":"method-not-implemented","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}