Hmbown/CodeWhale · error

Compaction summary response was unusable: no text was return

Error message

Compaction summary response was unusable: no text was returned.

What it means

validate_compaction_summary (crates/tui/src/compaction.rs:1125) rejects a summary that is empty after trim. The compaction path prefers failing - and keeping the full history - over replacing the session with an empty continuation checkpoint.

Source

Thrown at crates/tui/src/compaction.rs:1125

    let mut prompt = format!(
        "The previous handoff response was empty or a placeholder. Return a substantive factual \
continuation handoff. State the user objective, completed and current work, hard constraints, verified \
evidence, unresolved failures, and the single next action. Do not refuse, call tools, discuss \
checkpoint machinery, or return a placeholder. {COMPACTION_LANGUAGE_CONTRACT}"
    );
    if let Some(focus) = focus.map(str::trim).filter(|focus| !focus.is_empty()) {
        let _ = write!(
            prompt,
            "\n\nThe user asked this compaction to focus on: {focus}"
        );
    }
    prompt
}

fn validate_compaction_summary(summary: &str) -> Result<()> {
    let trimmed = summary.trim();
    if trimmed.is_empty() {
        anyhow::bail!("Compaction summary response was unusable: no text was returned.");
    }

    // Strip every non-word edge, not just ASCII punctuation. Providers can
    // return visually non-empty Unicode punctuation or emoji-only payloads;
    // neither is a usable continuation checkpoint. `is_alphanumeric` keeps
    // this language-neutral for CJK and other scripts without imposing a
    // prose-length heuristic.
    let normalized = trimmed
        .trim_matches(|ch: char| !ch.is_alphanumeric())
        .to_ascii_lowercase();
    if normalized.is_empty() {
        anyhow::bail!(
            "Compaction summary response was unusable: only whitespace or punctuation was returned."
        );
    }
    if matches!(
        normalized.as_str(),
        "no summary available"

View on GitHub (pinned to 8880682c63)

Solutions

  1. Retry compaction - a single empty response is usually stochastic
  2. Use a model with stronger instruction-following for the summary step
  3. Check the provider/gateway for content filtering or blocklists that empty responses
  4. Confirm the compaction model actually supports plain text output for the configured response format
Defensive patterns

Strategy: try-catch

Type guard

fn is_unusable_summary(msg: &str) -> bool {
    msg.contains("Compaction summary response was unusable")
}

Try / catch

// Retry once with a different model, then surface: never persist an empty checkpoint
match compact().await {
    Err(e) if is_unusable_summary(&e.to_string()) => compact_with_model(fallback_model).await,
    r => r,
}

Prevention

When it happens

Trigger: The summary model returns an empty assistant message (tool-call-only completion, response_format forcing empty output) or a gateway strips the content block.

Common situations: Small models with weak instruction-following asked to summarize very long histories; providers under content filtering that blank responses; misconfigured gateways.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/cee0ae934da6baf5. Report an issue: GitHub.