{"record":{"id":"cee0ae934da6baf5","repo":"Hmbown/CodeWhale","slug":"compaction-summary-response-was-unusable-no-text","errorCode":null,"errorMessage":"Compaction summary response was unusable: no text was returned.","messagePattern":"Compaction summary response was unusable: no text was returned\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/compaction.rs","lineNumber":1508,"sourceCode":"evidence, unresolved failures, and the single next action. Do not refuse, call tools, discuss \\\ncheckpoint machinery, or return a placeholder. {COMPACTION_LANGUAGE_CONTRACT}\"\n    );\n    if let Some(section) = operator_instructions_section(instructions) {\n        prompt.push_str(&section);\n    }\n    if let Some(focus) = focus.map(str::trim).filter(|focus| !focus.is_empty()) {\n        let _ = write!(\n            prompt,\n            \"\\n\\nThe user asked this compaction to focus on: {focus}\"\n        );\n    }\n    prompt\n}\n\nfn validate_compaction_summary(summary: &str) -> Result<()> {\n    let trimmed = summary.trim();\n    if trimmed.is_empty() {\n        anyhow::bail!(\"Compaction summary response was unusable: no text was returned.\");\n    }\n\n    // Strip every non-word edge, not just ASCII punctuation. Providers can\n    // return visually non-empty Unicode punctuation or emoji-only payloads;\n    // neither is a usable continuation checkpoint. `is_alphanumeric` keeps\n    // this language-neutral for CJK and other scripts without imposing a\n    // prose-length heuristic.\n    let normalized = trimmed\n        .trim_matches(|ch: char| !ch.is_alphanumeric())\n        .to_ascii_lowercase();\n    if normalized.is_empty() {\n        anyhow::bail!(\n            \"Compaction summary response was unusable: only whitespace or punctuation was returned.\"\n        );\n    }\n    if matches!(\n        normalized.as_str(),\n        \"no summary available\"","sourceCodeStart":1490,"sourceCodeEnd":1526,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/compaction.rs#L1490-L1526","documentation":"validate_compaction_summary bails when the model's summary response is empty after trimming whitespace. A compaction summary must provide usable continuation text; an empty response cannot serve as a checkpoint for the compacted conversation, so compaction aborts.","triggerScenarios":"The LLM returns an empty string or only whitespace as its compaction summary — e.g. a provider outage returning empty bodies, a truncated/malformed completion, or the model hitting an output token limit before emitting text.","commonSituations":"Provider-side failures during long-context summarization requests; rate-limited or degraded API responses; model misconfiguration producing no output.","solutions":["Retry compaction — transient provider issues often resolve","Check provider status/credentials and rate limits","Verify the model configured for compaction actually produces text output","Manually start a fresh session if compaction keeps failing"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if (!resp.choices?.[0]?.message?.content?.trim()) {\n  throw new Error('empty compaction summary');\n}","typeGuard":"const hasText = (s: string | null | undefined): s is string =>\n  typeof s === 'string' && s.trim().length > 0;","tryCatchPattern":"let summary = loop { match summarize().await { Ok(s) if !s.trim().is_empty() => break s, _ => continue } };","preventionTips":["Verify provider health and API keys before long compaction requests","Set a non-zero max output token limit for the summary call","Use a model known to produce text completions reliably","Retry on transient provider failures"],"tags":["compaction","empty-response","llm"],"backgroundTag":"empty-response-body","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}