Hmbown/CodeWhale · error
Compaction returned a tool call instead of a completed…
Error message
Compaction returned a tool call instead of a completed handoff; original conversation was preserved.
What it means
A compaction summary response must be plain text, not a tool invocation. If any content block is a ToolUse, the model tried to call a tool instead of finishing the summary handoff, so compaction aborts and the original conversation is preserved.
Solutions
- Disable tools / tool_choice for the compaction summary request (force text-only output).
- Retry compaction — the model may emit text on a second attempt.
- Check the summary prompt states it must return only text, not take actions.
- Use a model or configuration that does not auto-invoke tools for this request.
- No data lost: the original history is kept; re-run compaction after fixing.
Example fix
// before: tools available during compaction let resp = model.request(req).await?; // after: force plain text let resp = model.request(req.with_tools_disabled()).await?;
Defensive patterns
Strategy: validation
Validate before calling
fn has_tool_use(content: &[ContentBlock]) -> bool {
content.iter().any(|b| matches!(b, ContentBlock::ToolUse { .. }))
} Type guard
if has_tool_use(&response.content) { /* reject as non-summary */ } Try / catch
match compaction::summarize(&history) {
Err(e) if e.to_string().contains("tool call instead") => retry_text_only(),
other => other,
} Prevention
- Disable tool access for the compaction request
- Force text-only output (tool_choice none / no tools)
- Keep the summary prompt scoped to 'return text only'
- Preserve the original conversation until validation passes
When it happens
Trigger: The summary request completes but `response.content` contains at least one `ContentBlock::ToolUse` — the model emitted a tool call during compaction.
Common situations: A model/agent with tools enabled treats the summary prompt as another agent turn and starts calling tools; a misconfigured summary request exposes the tool catalog; aggressive agentic models (auto tool use) act instead of answering.
Related errors
- Compaction summary response was unusable: a placeholder was…
- Compaction coverage floor: a last-round user message was…
- Compaction coverage floor: checkpoint receipt was dropped…
- Compaction coverage floor
- Compaction coverage floor: last-round assistant output was…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/4d0bfd96c590fab4.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/compaction.rs:1674
&cost_route,
&response.usage,
);
// Usage above is already billed; a provider-declared incomplete
// summary must still fail rather than replace the session history
// with a fragment.
if codewhale_models::is_incomplete_stop_reason(response.stop_reason.as_deref()) {
anyhow::bail!(
"Compaction summary response incomplete: provider stop reason `{}`; the partial summary was not accepted.",
codewhale_models::stop_reason_detail(response.stop_reason.as_deref())
);
}
if response
.content
.iter()
.any(|block| matches!(block, ContentBlock::ToolUse { .. }))
{
anyhow::bail!(
"Compaction returned a tool call instead of a completed handoff; original conversation was preserved."
);
}
let summary = response
.content
.iter()
.filter_map(|block| match block {
ContentBlock::Text { text, .. } => Some(text.clone()),
_ => None,
})
.collect::<Vec<_>>()
.join("\n");
if let Err(error) = validate_compaction_summary(&summary) {
if quality_retry_used {
return Err(error.context(
"Compaction summary remained unusable after one conservative retry; \View on GitHub (pinned to 73e0f67d83)