shareAI-lab/learn-claude-code · error · WorkflowInputError
agent() cap reached ({AGENT_CAP})
Error message
agent() cap reached ({AGENT_CAP}) What it means
ExecutionLimits.claim_agent increments a run-wide counter on every agent() invocation and raises WorkflowInputError once it exceeds AGENT_CAP (1000). The cap applies across nested workflows because the same ExecutionLimits instance is shared by depth, preventing runaway recursion or generate-loops from spawning unbounded agent calls. Note the counter is never decremented — it counts total invocations, not concurrency (which the semaphore caps separately).
Source
Thrown at s16_workflow_runtime/code.py:426
def progress_event(self, ptype, **data):
self.progress.append({"type": ptype, **data})
line = " ".join(f"{k}={v}" for k, v in data.items())
print(f" progress {ptype:<16} {line}")
# -- Workflow Primitives --
class ExecutionLimits:
"""Shared run-wide limits, including nested workflows."""
def __init__(self):
self.agents = 0
self.semaphore = asyncio.Semaphore(CONCURRENCY)
def claim_agent(self):
self.agents += 1
if self.agents > AGENT_CAP:
raise WorkflowInputError(f"agent() cap reached ({AGENT_CAP})")
class ExecutionState:
"""Injected into the workflow script with the orchestration primitives."""
def __init__(self, task, journal, runner, budget, args, depth=0, limits=None):
self.task = task
self.journal = journal
self.runner = runner
self.budget = budget
self.args = args
self._depth = depth
self._phase = None
self._phases_seen = set()
self._limits = limits or ExecutionLimits()
def phase(self, title):
"""Start a phase; subsequent agent()s group under it. Upsert: emitting theView on GitHub (pinned to 985456f4ad)
Solutions
- Fix the loop/recursion termination — the cap is almost always a symptom of a runaway workflow, not the defect itself
- For legitimate large fan-outs, batch the work: aggregate items so each agent() call handles many, staying under 1000 calls
- Track usage via state and stop cleanly before the cap: guard with a counter of your own if you can run near 1000
Example fix
# before (runaway)
while not done:
result = state.agent("check status") # 'done' never becomes True
# after
for attempt in range(50):
result = state.agent("check status")
if result["done"]:
break Defensive patterns
Strategy: validation
Validate before calling
# inside the workflow, before fanning out:
PLANNED = len(items)
if state.limits.agents + PLANNED > AGENT_CAP:
# batch items so each agent() call covers several, or split into multiple runs
items = [items[i:i + 10] for i in range(0, len(items), 10)] Try / catch
try:
result = state.agent(prompt)
except WorkflowInputError as exc:
if "agent() cap reached" not in str(exc):
raise
state.task.update("halted: agent cap reached — check loop termination")
raise # a runaway loop must fail loudly; do not swallow Prevention
- Bound every loop that calls agent() with an explicit iteration cap
- Batch fan-outs so 1000 calls cover arbitrarily many items
- Treat hitting AGENT_CAP as a termination bug to fix, not a limit to raise
When it happens
Trigger: A loop whose condition never turns false calling agent() each iteration. Recursive sub-workflows that spawn agents before recursing. Legitimate very large fan-outs (map over >1000 items) hitting the hard ceiling.
Common situations: Termination bugs in goal-loop style workflows. Batch jobs sized above the cap after data growth. Recursion that passes the same limits object down through nested runs.
Related errors
- token budget exceeded ({self._spent + n} > {self._total})
- token budget exceeded
- workflow() nesting is one level only
- Max 20 todos
- Max 20 todos allowed
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/47284f1d72350b40.
Report an issue: GitHub.