JuliusBrussee/caveman · error
cave_subagent_depth_limit
cave_subagent_depth_limit
Error message
cave_subagent_depth_limit
What it means
Subagent nesting depth is capped at min(parentOptions.maxSubagentDepth ?? DEFAULT_SUBAGENT_DEPTH_LIMIT, ABSOLUTE_SUBAGENT_DEPTH_LIMIT) — the absolute ceiling is 8 and the default is 2. A subagent already at the deepest allowed level that tries to spawn another throws cave_subagent_depth_limit.
Source
Thrown at packages/agent/src/runtime.ts:3883
const runtime = toolDefinition.runtime;
if (runtime?.kind !== "subagent") throw new Error("cave_subagent_runtime_missing");
if (params === null || typeof params !== "object" || Array.isArray(params) ||
typeof (params as { task?: unknown }).task !== "string") {
throw new Error("cave_subagent_arguments_invalid");
}
const task = (params as { task: string }).task;
if (task.length > runtime.maxInputChars) throw new Error("cave_subagent_input_limit");
const calls = usage.calls.get(toolDefinition.name) ?? 0;
if (calls >= runtime.maxCalls) throw new Error("cave_subagent_call_budget");
// Reserve synchronously before any await so parallel Pi tool dispatch cannot
// pass the same maxCalls check twice.
usage.calls.set(toolDefinition.name, calls + 1);
const depth = executionContext.depth;
const depthLimit = Math.min(
parentOptions.maxSubagentDepth ?? DEFAULT_SUBAGENT_DEPTH_LIMIT,
ABSOLUTE_SUBAGENT_DEPTH_LIMIT,
);
if (depth + 1 > depthLimit) throw new Error("cave_subagent_depth_limit");
// The wallet is carved here, still synchronously, for the same reason: two
// subagents dispatched in one turn must not both be funded out of the same
// remaining budget.
const walletAmount = parentMeter === undefined
? undefined
: parentMeter.denomination === "usd" ? runtime.maxCostUsd : runtime.maxTokens;
if (parentMeter !== undefined && walletAmount === undefined) {
throw new Error("cave_subagent_wallet_denomination_unavailable");
}
const carve = parentMeter === undefined || walletAmount === undefined
? undefined
: parentMeter.carve(walletAmount);
if (parentMeter !== undefined && carve === undefined) {
throw new Error("cave_subagent_wallet_unavailable");
}
let releaseAdmission: (() => void) | undefined;
try {
releaseAdmission = admitSubagent(executionContext.invocationState);View on GitHub (pinned to 766dce6b13)
Solutions
- Raise runOptions.maxSubagentDepth — noting the absolute cap of 8 still applies
- Make deep agents solve the task in-run instead of delegating further
- Tell subagents their depth budget in the prompt so they stop delegating near the cap
Example fix
// before
run(agent, { maxSubagentDepth: 2 });
// after
run(agent, { maxSubagentDepth: 4 }); // still capped at ABSOLUTE_SUBAGENT_DEPTH_LIMIT (8) Defensive patterns
Strategy: validation
Validate before calling
const ABSOLUTE_DEPTH = 8;
const limit = Math.min(options.maxSubagentDepth ?? 2, ABSOLUTE_DEPTH);
if (context.depth + 1 > limit) {
return { error: `subagent depth limit (${limit}) reached — complete the task in this run` };
} Prevention
- Set maxSubagentDepth deliberately (default 2, absolute cap 8)
- Include the remaining depth budget in subagent prompts so they stop delegating near the cap
- Design delegation as breadth (siblings) rather than depth (children of children)
When it happens
Trigger: A subagent spawning a subagent spawning a subagent past the configured depth; recursive decomposition where each level delegates the same unsolved problem downward; run options validating maxSubagentDepth above 8 still get clamped to 8.
Common situations: Recursive research or fix loops with no depth guard in prompts; maxSubagentDepth lowered for cost control while prompts still encourage delegation; agents passing their own delegation habit to children.
Related errors
- cave_subagent_invocation_limit
- cave_subagent_concurrency_limit
- cave_subagent_call_budget
- cave_subagent_definition_cycle
- cave_claude_subagent_bridge_unavailable
AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18).
Data as JSON: /api/errors/27d86b8f225c6d8d.
Report an issue: GitHub.