zeroclaw-labs/zeroclaw · error
Agent loop aborted: repeated prompt-required tool call '{too
Error message
Agent loop aborted: repeated prompt-required tool call '{tool_name}' with identical arguments before approval. What it means
In tool-call preparation, ZeroClaw tracks signatures (tool name + arguments) of prompt-approval-required shell calls across the whole loop. When the model emits a shell call whose signature was already recorded in a previous round and still has not been approved, prepare_tool_calls aborts the turn — an explicit infinite-approval-loop guard rather than letting the model re-request the same command forever. A status delta and a WARN log with the tool and scrubbed arguments precede the bail.
Source
Thrown at crates/zeroclaw-runtime/src/agent/turn/call_prep.rs:217
.with_attrs(::serde_json::json!({
"model": ctx.model,
"iteration": iteration + 1,
"tool": tool_name.clone(),
"arguments": scrub_credentials(&tool_args.to_string()),
"result": repeated,
"trace_id": ctx.turn_id,
})),
"tool_call_result"
);
if let Some(tx) = ctx.on_delta {
let _ = tx
.send(StreamDelta::Status(format!(
"\u{274c} {}: {}\n",
tool_name, repeated
)))
.await;
}
anyhow::bail!("{repeated}");
}
}
// ── Approval hook ────────────────────────────────
let approved = match gate_tool_approval(ctx, &tool_name, &tool_args, iteration).await {
ApprovalGateOutcome::Proceed { approved } => approved,
ApprovalGateOutcome::Deny(outcome) | ApprovalGateOutcome::Replace(outcome) => {
// Streaming consumers see the denied/replaced call and its
// synthesized result (e.g. a DenyWithEdit replacement) as a
// ToolCall/ToolResult pair, as the direct path always did.
if let Some(tx) = ctx.event_tx {
emit_tool_call_pair(tx, call, &outcome).await;
}
ordered_results[idx] =
Some((tool_name.clone(), call.tool_call_id.clone(), outcome));
continue;
}
};View on GitHub (pinned to 88bb9c8533)
Solutions
- Resolve the pending approval: run interactively and approve/deny, or adjust the approval policy so this specific command class proceeds without a prompt.
- Change the system prompt so the model varies arguments or asks the user instead of repeating an identical call.
- Inspect the WARN 'tool_call_result' log for the exact tool and scrubbed arguments, then fix whatever output keeps making the model retry identically (e.g. a failing command's error).
- If the environment is legitimately non-interactive, scope approval requirements down for the commands that run there.
Example fix
# before — non-interactive run, model repeats `shell: cargo test` awaiting approval that never comes # after — pre-approve deterministic commands or instruct the model: # "`cargo test` is pre-approved. Run it once; if it fails, change the command before rerunning." # and/or relax the approval policy for that command class in the agent's risk profile
Defensive patterns
Strategy: try-catch
Try / catch
Catch the abort at the turn boundary, read the WARN 'tool_call_result' log for tool name + scrubbed arguments, then either resume the turn after the approval is granted/policy adjusted, or surface the tool call to the user for an explicit decision. Do not auto-retry the identical turn — it will abort again.
Prevention
- Keep approval prompts answerable: run approval-requiring agents interactively or provide an approval hook
- Pre-approve deterministic read-only commands in the risk profile for non-interactive channels
- Prompt the model to change arguments (not repeat them) after a failed command
- Monitor for duplicate tool-call signatures as an early loop signal
When it happens
Trigger: The model re-issues the exact same shell command after the earlier identical call was denied, replaced, or recorded as a duplicate; a non-interactive channel (cron, gateway) where the approval prompt can never be answered; the model retrying a failing command with identical arguments instead of changing them.
Common situations: Risk profile flags shell for approval in an environment with no human to approve; agent stuck in a retry loop on a command that keeps failing; approval hooks that deny without telling the model what to change.
Related errors
- Agent exceeded maximum tool iterations ({max_iterations})
- ACP request_permission timed out after {:?}
- ACP returned unknown permission optionId: {other}
- ACP returned unexpected permission outcome: {other}
- approval prompts are not supported over interaction replies
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/3d43c6b3d2f605ef.
Report an issue: GitHub.