{"record":{"id":"72747f065c9a2722","repo":"zeroclaw-labs/zeroclaw","slug":"agent-exceeded-maximum-tool-iterations-max-itera","errorCode":null,"errorMessage":"Agent exceeded maximum tool iterations ({max_iterations})","messagePattern":"Agent exceeded maximum tool iterations \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/agent/turn/max_iter.rs","lineNumber":48,"sourceCode":"    mut new_messages_out: Option<&mut Vec<ChatMessage>>,\n) -> Result<String> {\n    ::zeroclaw_log::record!(\n        WARN,\n        ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)\n            .with_category(::zeroclaw_log::EventCategory::Agent)\n            .with_outcome(::zeroclaw_log::EventOutcome::Failure)\n            .with_attrs(::serde_json::json!({\n                \"model\": model,\n                \"max_iterations\": max_iterations,\n                \"trace_id\": turn_id,\n            })),\n        \"tool_loop_exhausted\"\n    );\n\n    // ErrorAtCap callers (embedders driving Agent::turn) treat the cap as a\n    // control signal: bail instead of spending another LLM call on a summary.\n    if knobs.max_iteration_behavior == MaxIterationBehavior::ErrorAtCap {\n        anyhow::bail!(\"Agent exceeded maximum tool iterations ({max_iterations})\")\n    }\n\n    // Graceful shutdown: ask the LLM for a final summary without tools\n    ::zeroclaw_log::record!(\n        WARN,\n        ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)\n            .with_category(::zeroclaw_log::EventCategory::Agent)\n            .with_outcome(::zeroclaw_log::EventOutcome::Unknown)\n            .with_attrs(::serde_json::json!({\"max_iterations\": max_iterations})),\n        \"Max iterations reached, requesting final summary\"\n    );\n    let tool_calls_stripped =\n        crate::agent::history_pruner::strip_orphaned_tool_calls_from_assistants(history);\n    let tool_messages_removed =\n        crate::agent::history_pruner::remove_orphaned_tool_messages(history).removed;\n    if tool_calls_stripped > 0 || tool_messages_removed > 0 {\n        ::zeroclaw_log::record!(\n            WARN,","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/agent/turn/max_iter.rs#L30-L66","documentation":"When the tool loop exhausts max_iterations and LoopKnobs.max_iteration_behavior is ErrorAtCap, finish_after_max_iterations bails immediately with this error instead of spending one more LLM call on a graceful summary — embedders driving Agent::turn use it as a control signal ('cap reached'). The graceful path (a tools-free final summary) only runs under the non-ErrorAtCap behavior. A WARN 'tool_loop_exhausted' event with the model and cap is logged first.","triggerScenarios":"A task legitimately needs more tool rounds than the configured cap; the model loops without converging (repeated failing tool calls); an embedded Agent::turn integration running with the default ErrorAtCap behavior on long multi-step jobs.","commonSituations":"Large refactors or repo-wide scans under a default iteration cap; a tool returning errors so the model keeps retrying; embedders unaware that ErrorAtCap turns the cap into a hard error.","solutions":["Raise max_iterations for tasks that legitimately need more tool rounds.","If you want a final answer instead of an error at the cap, set the max-iteration behavior to the graceful summary path.","Inspect the loop logs for non-convergence: repeated identical tool calls or failing tools burning iterations, and fix the underlying tool/prompt issue.","For embedded use, catch this error and treat it as 'budget exhausted' — resume the turn with a fresh budget if the work should continue."],"exampleFix":"// before — embedder default treats the cap as a hard error\nlet result = agent.turn(request).await; // bails: exceeded maximum tool iterations\n\n// after — opt into graceful summary at the cap, or raise the cap\n// knobs: max_iteration_behavior = MaxIterationBehavior::Graceful (summary instead of error)\n// or: max_iterations = 80","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"Catch 'Agent exceeded maximum tool iterations', then choose a fallback: resume the turn with a raised cap if the work should continue, or accept the accumulated transcript/streamed output as partial results. Under ErrorAtCap this error is a control signal — treat it as 'budget exhausted', not a crash.","preventionTips":["Size max_iterations to the task (repo-wide work needs more than chat-scale defaults)","Watch per-turn iteration counts and alert near the cap","Fix non-convergent loops (repeated failing tool calls) instead of only raising the cap","Pick the max-iteration behavior deliberately when embedding Agent::turn"],"tags":["agent-loop","max-iterations","tools","resource-limits"],"backgroundTag":"tool-loop-exhausted","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}