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

  1. Flatten the workflow: have the deepest subagent return results instead of spawning more agents
  2. Raise `task.maxRecursionDepth` in settings (e.g. to 3) if deeper nesting is intentional
  3. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/1472ddaa57124ae3. Report an issue: GitHub.