zeroclaw-labs/zeroclaw · error
Agent loop aborted by loop detector: {msg}
Error message
Agent loop aborted by loop detector: {msg} What it means
collect_tool_results feeds every successful tool outcome into loop_detector.record(tool, args, output). When detection escalates past Warning (advice appended to history) and Block (output replaced with feedback) to Break — the circuit breaker — the whole turn aborts with the detector's message. This is the last-resort protection against runaway repetitive tool calling.
Source
Thrown at crates/zeroclaw-runtime/src/agent/turn/results_collect.rs:120
format!("[Loop Detection — BLOCKED] {msg}"),
);
}
crate::agent::loop_detector::LoopDetectionResult::Break(msg) => {
::zeroclaw_log::record!(
WARN,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)
.with_category(::zeroclaw_log::EventCategory::Tool)
.with_outcome(::zeroclaw_log::EventOutcome::Failure)
.with_attrs(::serde_json::json!({
"model": model,
"iteration": iteration + 1,
"tool": tool_name,
"message": msg,
"trace_id": turn_id,
})),
"loop_detector_circuit_breaker"
);
anyhow::bail!("Agent loop aborted by loop detector: {msg}");
}
}
}
let canonical_output =
canonicalize_tool_result_media_markers_for(&tool_name, &outcome.output);
let mut result_output = truncate_tool_result(&canonical_output, max_tool_result_chars);
// Append HMAC receipt to tool result when receipts are enabled
if let Some(ref receipt) = outcome.receipt {
::zeroclaw_log::record!(
DEBUG,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)
.with_category(::zeroclaw_log::EventCategory::Tool)
.with_attrs(::serde_json::json!({"tool": tool_name, "receipt": receipt})),
"Tool receipt generated"
);
result_output = format!("{result_output}\n\n[receipt: {receipt}]");
if let Some(store) = collected_receipts
&& let Ok(mut v) = store.lock()View on GitHub (pinned to 88bb9c8533)
Solutions
- Read the detector msg plus the earlier Warning/Block log entries to identify the repeating tool and arguments
- Fix the tool output or prompt so the model can act on the result (clearer text, structured output, explicit completion markers)
- Switch to a stronger model or add explicit stop conditions to the system prompt
- Only after fixing the repetition, consider tuning loop-detector thresholds
Example fix
// before: system prompt gives no completion criteria "Keep working on the task." // after: bound the loop explicitly "Attempt each step once. If a tool result repeats or you already have the answer, summarize findings and stop."
Defensive patterns
Strategy: validation
Validate before calling
fn is_repetitive(calls: &[ToolCall], window: usize) -> bool {
let key = |c: &ToolCall| (c.name.clone(), c.arguments.to_string());
if calls.len() < window { return false; }
let last = key(&calls[calls.len() - 1]);
calls[calls.len() - window..].iter().filter(|c| key(c) == last).count() >= window
} Try / catch
match agent.run_turn(req).await {
Err(ref e) if e.to_string().starts_with("Agent loop aborted by loop detector") => {
// inspect which tool/args repeated from logs; fix prompt/tool output before retry
}
other => other,
} Prevention
- Give tools unambiguous, structured outputs the model can act on
- Add explicit stop conditions to system prompts for open-ended tasks
- Vary arguments when retrying — identical name+args is what the detector keys on
- Watch for Warning/Block feedback messages in history; they precede the breaker
When it happens
Trigger: The model repeatedly issues effectively identical tool calls (same name and arguments), ignores injected Warning and Block feedback messages, and keeps going; only successful outcomes are recorded, so a pattern needs succeeding calls to trip the breaker.
Common situations: Model fixated on a tool whose output it misreads (unparseable format, truncated result); prompts with no termination criterion; under-powered models looping on one step; tools whose errors look like success.
Related errors
- Agent loop aborted: repeated prompt-required tool call '{too
- Agent exceeded maximum tool iterations ({max_iterations})
- Final summary LLM call timed out after {step_secs}s (step_ti
- LLM call cancelled by hook: {reason}
- Budget exceeded: ${:.4} of ${:.2} {:?} limit. Cannot make fu
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/a6bb395a99fd1890.
Report an issue: GitHub.