abi/screenshot-to-code · error · Exception
Agent exceeded max tool turns
Error message
Agent exceeded max tool turns
What it means
Generic Exception raised at the end of _run_with_session when the agent exhausts its hardcoded 30-step tool loop (for _ in range(max_steps) with max_steps = 30) without the model ever producing a tool-call-free final turn. Each iteration is one model turn; the loop only exits early when turn.tool_calls is empty (final answer).
Source
Thrown at backend/agent/engine.py:327
len(tool_result.updated_content), "tool_result"
)
await self._send(
"toolResult",
data={
"name": tool_call.name,
"output": tool_result.summary,
"ok": tool_result.ok,
},
event_id=tool_event_id,
)
executed_tool_calls.append(
ExecutedToolCall(tool_call=tool_call, result=tool_result)
)
await session.append_tool_results(turn, executed_tool_calls)
raise Exception("Agent exceeded max tool turns")
async def run(self, model: Llm, prompt_messages: List[ChatCompletionMessageParam]) -> str:
self.tool_runtime.input_images = self._extract_input_images(prompt_messages)
seed_file_state_from_messages(self.file_state, prompt_messages)
if self.recorder is not None:
self.recorder.record_run_start(model, prompt_messages)
session = create_provider_session(
model=model,
prompt_messages=prompt_messages,
should_generate_images=self.should_generate_images,
openai_api_key=self.openai_api_key,
openai_base_url=self.openai_base_url,
anthropic_api_key=self.anthropic_api_key,
gemini_api_key=self.gemini_api_key,
replicate_api_key=self.replicate_api_key,
# Only advertise extraction when the request actually contains aView on GitHub (pinned to d026163f58)
Solutions
- Use a stronger model that converges in fewer turns.
- Tighten the user prompt so the model knows to output final code and stop calling tools.
- Raise max_steps in backend/agent/engine.py:219 if the workload legitimately needs more turns.
- Check the run recording (recorder logs every turn) to see which tool the model loops on and fix that tool's result so the model can proceed.
Example fix
# before (backend/agent/engine.py) max_steps = 30 # after max_steps = 50 # still bounded, but allows larger tasks
Defensive patterns
Strategy: try-catch
Try / catch
try:
html = await engine.run(model, messages)
except Exception as e:
if "exceeded max tool turns" in str(e):
# retry with stronger model or simplified prompt
... Prevention
- Keep generation prompts explicit about producing final code without further tool calls.
- Prefer models that converge; test new model integrations with small screenshots first.
- If you control the engine, make max_steps configurable rather than hardcoded so callers can tune it.
When it happens
Trigger: The model keeps requesting tool calls (editing files, generating images, reading state) for 30 consecutive turns and never emits a plain text final response.
Common situations: Under-powered models stuck in a tool loop, prompts that never tell the model when to stop, or a task too large for 30 turns (big multi-file generation with image assets).
Related errors
- Generation finished without producing any output.
- Generation stopped: this variant exceeded its resource limit
- Inference timed out
- Request timed out
AI-assisted analysis of abi/screenshot-to-code@d026163f58 (2026-08-14).
Data as JSON: /api/errors/be99c43d10188f15.
Report an issue: GitHub.