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 the

View on GitHub (pinned to 985456f4ad)

Solutions

  1. Fix the loop/recursion termination — the cap is almost always a symptom of a runaway workflow, not the defect itself
  2. For legitimate large fan-outs, batch the work: aggregate items so each agent() call handles many, staying under 1000 calls
  3. 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

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


AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14). Data as JSON: /api/errors/47284f1d72350b40. Report an issue: GitHub.