can1357/oh-my-pi · error · StructuredSubagentError
Cannot spawn another agent at task depth ${taskDepth}; maxim
Error message
Cannot spawn another agent at task depth ${taskDepth}; maximum depth is ${maxDepth}. What it means
Thrown in preflight when the current task depth (`request.session.taskDepth`, default 0) already equals or exceeds the configured `task.maxRecursionDepth` setting (default 2). The library caps how deeply subagents may nest to prevent runaway recursion. `canSpawnAtDepth` returns false and `assertDepthAndSpawnAllowed` raises a preflight StructuredSubagentError.
Source
Thrown at packages/coding-agent/src/task/structured-subagent.ts:219
function assertPlanControlsAllowed(request: StructuredSubagentRequest, planMode: boolean): void {
if (!planMode) return;
const isolation = request.isolation;
if (
isolation &&
(Object.hasOwn(isolation, "requested") || Object.hasOwn(isolation, "apply") || Object.hasOwn(isolation, "merge"))
) {
throw new StructuredSubagentError(
"preflight",
"Subagent isolation, apply, and merge controls are unavailable in plan mode.",
);
}
}
function assertDepthAndSpawnAllowed(request: StructuredSubagentRequest, agentName: string): void {
const taskDepth = request.session.taskDepth ?? 0;
const maxDepth = request.session.settings.get("task.maxRecursionDepth") ?? 2;
if (!canSpawnAtDepth(maxDepth, taskDepth)) {
throw new StructuredSubagentError(
"preflight",
`Cannot spawn another agent at task depth ${taskDepth}; maximum depth is ${maxDepth}.`,
);
}
const blockedAgent = request.blockedAgent ?? $env.PI_BLOCKED_AGENT;
if (blockedAgent && blockedAgent === agentName) {
throw new StructuredSubagentError(
"preflight",
`Cannot spawn ${blockedAgent} agent from within itself (recursion prevention). Use a different agent type.`,
);
}
const spawnPolicy = resolveSpawnPolicy(request.session.getSessionSpawns());
if (!spawnPolicy.enabled || (spawnPolicy.allowedAgents !== null && !spawnPolicy.allowedAgents.includes(agentName))) {
throw new StructuredSubagentError(
"preflight",
`Cannot spawn '${agentName}'. Allowed: ${spawnPolicy.allowedErrorText}`,
);
}View on GitHub (pinned to 9690622007)
Solutions
- Flatten the workflow: have the deepest subagent return results instead of spawning more agents
- Raise `task.maxRecursionDepth` in settings (e.g. to 3) if deeper nesting is intentional
- Check `session.taskDepth` before calling and skip nested spawning at the limit
Example fix
// settings before
{ "task.maxRecursionDepth": 1 }
// after
{ "task.maxRecursionDepth": 2 } Defensive patterns
Strategy: validation
Validate before calling
const depth = session.taskDepth ?? 0;
const maxDepth = session.settings.get("task.maxRecursionDepth") ?? 2;
if (depth >= maxDepth) return fallbackResult(); // skip spawning
await task(request); Try / catch
try {
await task(req);
} catch (e) {
if (e instanceof StructuredSubagentError && e.message.includes("maximum depth")) {
return doWorkInline(); // handle without nesting
}
throw e;
} Prevention
- Track taskDepth in nested agent prompts and stop spawning near the limit
- Keep task.maxRecursionDepth consistent across environments
- Design workflows to be shallow; prefer returning data over spawning more agents
When it happens
Trigger: A subagent (depth 1) or deeper descendant tries to spawn another subagent when `taskDepth >= task.maxRecursionDepth`; e.g. depth 2 with the default max of 2, or depth 1 with maxRecursionDepth set to 1.
Common situations: Deeply nested agent workflows (agent spawns agent spawns agent); lowering `task.maxRecursionDepth` in settings below the existing nesting; recursive task-decomposition prompts that let the subagent re-invoke the task tool.
Related errors
- Cannot spawn ${blockedAgent} agent from within itself (recur
- Agent "${agentName}" is disabled in settings. Enable it via
- Subagent isolated execution requires task.isolation.mode to
- No model configured
- Azure OpenAI base URL is required. Set AZURE_OPENAI_BASE_URL
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/1472ddaa57124ae3.
Report an issue: GitHub.