{"record":{"id":"f28a7c3689b2eb33","repo":"Hmbown/CodeWhale","slug":"compaction-failed-after-max-retries-retries","errorCode":null,"errorMessage":"Compaction failed after {MAX_RETRIES} retries","messagePattern":"Compaction failed after (.+?) retries","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/compaction.rs","lineNumber":977,"sourceCode":"                drop(removed);\n                return Ok(CompactionResult {\n                    messages: sanitize_retained_messages(msgs),\n                    summary_prompt: prompt,\n                    retries_used: attempt.saturating_add(quality_retries),\n                });\n            }\n            Err(e) => {\n                // Only retry on transient errors\n                if !is_transient_error(&e) {\n                    return Err(e);\n                }\n                last_error = Some(e);\n            }\n        }\n    }\n\n    Err(last_error\n        .unwrap_or_else(|| anyhow::anyhow!(\"Compaction failed after {MAX_RETRIES} retries\")))\n}\n\nfn build_compaction_summary_block_text(summary: &str, anchors: &str) -> String {\n    let summary = summary.trim();\n    let summary = if summary.is_empty() {\n        \"(no summary available)\"\n    } else {\n        summary\n    };\n    let mut text = format!(\"{SUMMARY_HEADER}\\n\\n{summary}\");\n    text.push_str(anchors);\n    text\n}\n\n/// Codex-parity replacement history: the most recent plain user messages,\n/// selected newest-first within a fixed token budget and restored to\n/// transcript order. The oldest selected message is truncated to fit rather\n/// than dropped whole.","sourceCodeStart":959,"sourceCodeEnd":995,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/compaction.rs#L959-L995","documentation":"compact_messages_safe retries transient failures (network, rate limit, timeout - never context overflow, which needs the smaller-input ladder) MAX_RETRIES=3 times with 1s/2s/4s backoff. This error (crates/tui/src/compaction.rs:977) means every attempt failed; the original message history is never corrupted - the function returns Err instead.","triggerScenarios":"Sustained 429 rate limiting across the whole ~7s retry window; network down or DNS failing for the full window; provider outage where each summarization attempt times out.","commonSituations":"Free-tier keys hitting org-wide limits; laptop sleep/resume mid-compaction; provider incidents; a proxy that resets long request durations.","solutions":["Wait 30-60s and trigger compaction again - session history is intact","Check the quota/rate-limit dashboard for the active key","Verify basic reachability of the provider endpoint (curl) before retrying","If it persists, point compaction at a different model or provider temporarily","If the last error is genuinely absent from the message, look for upstream logs - the fallback arm fires only when the loop exited without capturing one"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"fn is_compaction_retry_exhausted(msg: &str) -> bool {\n    msg.contains(\"Compaction failed after\") && msg.contains(\"retries\")\n}","tryCatchPattern":"// The library already did 3 retries with 1s/2s/4s backoff; add a slower outer tier\nmatch compact_now().await {\n    Err(e) if is_compaction_retry_exhausted(&e.to_string()) => {\n        tokio::time::sleep(Duration::from_secs(60)).await;\n        compact_now().await // history is intact, retry is safe\n    }\n    r => r,\n}","preventionTips":["Keep provider quota headroom before triggering compaction","Compact earlier so summaries are small and requests are short","Treat persistent exhaustion as an outage signal, not a bug - check status pages"],"tags":["compaction","retry","rate-limit","network"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}