shareAI-lab/learn-claude-code · error · GoalError
max_turns must be at least 1
Error message
max_turns must be at least 1
What it means
AgentSession was constructed with max_turns that is not None and is less than 1 (s17_goal_loop/code.py:541). max_turns bounds the agentic loop (each turn = one model call/tool round); zero or negative turns would forbid even one query, so the constructor rejects it.
Source
Thrown at s17_goal_loop/code.py:541
},
},
]
class AgentSession:
"""A small real agent loop with a goal Stop hook at the return boundary."""
def __init__(
self,
client: Any,
model: str,
goal: GoalController,
workdir: Path,
max_turns: int | None = None,
background_running: Callable[[], bool] | None = None,
):
if max_turns is not None and max_turns < 1:
raise GoalError("max_turns must be at least 1")
self.client = client
self.model = model
self.goal = goal
self.workdir = workdir.resolve()
self.max_turns = max_turns
self.background_running = background_running or (lambda: False)
self.messages: list[dict[str, Any]] = []
self.total_tokens = 0
self.hooks: dict[str, list[Callable[..., Any]]] = {
"UserPromptSubmit": [],
"PreToolUse": [],
"PostToolUse": [],
"Stop": [],
}
self.register_hook("PreToolUse", self._permission_hook)
self.register_hook("PreToolUse", self._log_hook)
self.register_hook("PostToolUse", self._large_output_hook)
self.register_hook("UserPromptSubmit", self._context_hook)View on GitHub (pinned to 985456f4ad)
Solutions
- Use max_turns=None for unlimited, or an integer >= 1 for a bounded loop
- Validate parsed config/CLI values before constructing the session
- Guard arithmetic that derives max_turns from another number
Example fix
# before session = AgentSession(client, model, goal, workdir, max_turns=0) # after session = AgentSession(client, model, goal, workdir, max_turns=None)
Defensive patterns
Strategy: validation
Validate before calling
max_turns = int(os.getenv("MAX_TURNS", 0)) or None # 0/absent -> unlimited
if max_turns is not None and max_turns < 1:
raise SystemExit("MAX_TURNS must be >= 1 or unset for unlimited")
session = AgentSession(client, model, goal, workdir, max_turns=max_turns) Type guard
def is_valid_max_turns(value: object) -> bool:
return value is None or (isinstance(value, int) and not isinstance(value, bool) and value >= 1) Prevention
- Use None for unlimited turns; 0 is invalid, not 'off'
- Validate parsed CLI/config numbers before constructing AgentSession
- Watch arithmetic like max_turns - 1 that can dip below 1 at edges
When it happens
Trigger: Instantiating AgentSession(..., max_turns=0) or max_turns=-2. Also passing a CLI/config value like --max-turns 0 that flows into the constructor unvalidated.
Common situations: Interpreting max_turns=0 as 'unlimited' (the library uses None for unlimited); arithmetic on user input (e.g. turns - 1) dipping below 1; config parsers yielding 0 for missing numeric fields.
Related errors
- block_cap must be at least 1
- goal evaluator must return a JSON object
- goal evaluator response requires non-empty 'reason'
- goal condition cannot be empty
- goal condition cannot exceed {MAX_GOAL_LENGTH} characters
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/3d8d4719b372a259.
Report an issue: GitHub.