aaif-goose/goose · error
No agent-visible tool pair found for tool id: {}
Error message
No agent-visible tool pair found for tool id: {} What it means
Before summarizing a tool call, goose gathers the agent-visible messages for the session and requires BOTH a MessageContent::ToolRequest and a MessageContent::ToolResponse whose id equals the requested tool id. This error means one half of the pair is missing (or the id matches nothing), so the call cannot be summarized.
Source
Thrown at crates/goose/src/context_mgmt/mod.rs:439
})
})
.cloned()
.collect::<Vec<_>>();
let matching_messages =
Conversation::new_unvalidated(matching_messages).agent_visible_messages();
let has_request = matching_messages.iter().any(|message| {
message.content.iter().any(
|content| matches!(content, MessageContent::ToolRequest(request) if request.id == tool_id),
)
});
let has_response = matching_messages.iter().any(|message| {
message.content.iter().any(
|content| matches!(content, MessageContent::ToolResponse(response) if response.id == tool_id),
)
});
if !has_request || !has_response {
return Err(anyhow::anyhow!(
"No agent-visible tool pair found for tool id: {}",
tool_id
));
}
Ok(matching_messages)
}
pub async fn summarize_tool_call(
provider: &dyn Provider,
model_config: &ModelConfig,
session_id: &str,
conversation: &Conversation,
tool_id: &str,
) -> Result<Message> {
let matching_messages = agent_visible_tool_pair(conversation, tool_id)?;
let formatted = matching_messages
.iter()View on GitHub (pinned to 3810898a74)
Solutions
- Verify the tool id refers to a completed call in the CURRENT conversation — both a ToolRequest and a ToolResponse with that exact id must be present in agent-visible messages
- If the tool is still running, wait for its response before summarizing
- Re-discover valid ids by scanning the live conversation instead of using logged/historical ids
Defensive patterns
Strategy: validation
Validate before calling
use goose::messages::{MessageContent, Conversation};
fn has_agent_visible_tool_pair(conversation: &Conversation, tool_id: &str) -> bool {
let mut has_request = false;
let mut has_response = false;
for m in conversation.messages().iter().filter(|m| m.is_agent_visible()) {
for c in &m.content {
match c {
MessageContent::ToolRequest(r) if r.id == tool_id => has_request = true,
MessageContent::ToolResponse(r) if r.id == tool_id => has_response = true,
_ => {}
}
}
}
has_request && has_response
}
// before summarize_tool_call:
if !has_agent_visible_tool_pair(&conversation, tool_id) { /* skip or re-fetch the id */ } Try / catch
match summarize_tool_call(provider, &model_config, session_id, &conversation, tool_id).await {
Err(e) if e.to_string().starts_with("No agent-visible tool pair found") => {
// the id is stale or the call is incomplete: re-scan the live conversation for valid ids
}
other => other?,
} Prevention
- Take tool ids from the current in-memory conversation, never from logs or earlier sessions
- Only summarize completed calls (response received)
- Re-validate ids after any compaction or truncation step
When it happens
Trigger: Calling summarize_tool_call with a tool id that is stale (from before a compaction/truncation that dropped one half), a request whose response has not arrived yet (tool still running), or an id typo. Messages hidden from the agent also never match.
Common situations: Summarizing old tool calls after context truncation removed the request or response; summarizing while the tool is still executing; replaying a logged tool id against a different conversation.
Related errors
- Cannot resume with provider or model changes because provide
- Failed to compact: context limit exceeded even after removin
- Responses function_call output missing call_id and id
- Missing tool_use id
- Missing tool_use name
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/f85cb09318df7a72.
Report an issue: GitHub.