can1357/oh-my-pi · error · StructuredSubagentError

Cannot spawn '${agentName}'. Allowed: ${spawnPolicy.allowedE

Error message

Cannot spawn '${agentName}'. Allowed: ${spawnPolicy.allowedErrorText}

What it means

Thrown in preflight when session spawn policy disallows the requested agent. `resolveSpawnPolicy(request.session.getSessionSpawns())` yields an allowlist (`allowedAgents`) and enabled flag; if spawns are disabled or the agent is not on the allowlist, the error lists the permitted agents via `allowedErrorText`.

Source

Thrown at packages/coding-agent/src/task/structured-subagent.ts:233

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}`,
		);
	}
}

/**
 * Resolve every policy shared by task and eval before allocating artifacts or
 * dispatching work. Callers translate {@link StructuredSubagentError} into
 * their own wire-level error surface.
 */
export async function resolveEffectiveSubagentPolicy(
	request: StructuredSubagentRequest,
): Promise<EffectiveSubagentPolicy> {
	await request.session.settings.reloadFromDisk();
	const spawnPolicy = resolveSpawnPolicy(request.session.getSessionSpawns());
	const agentName = request.agent?.trim() || spawnPolicy.defaultAgent;
	const planMode = request.session.getPlanModeState?.()?.enabled === true;

View on GitHub (pinned to 9690622007)

Solutions

  1. Request one of the agents listed in the error's `Allowed:` text
  2. Reconfigure the session's spawn policy (getSessionSpawns / session spawn settings) to include the desired agent
  3. Enable session spawning if `spawnPolicy.enabled` is false

Example fix

// before
await task({ agent: "explorer" }); // not allowed
// after
await task({ agent: "researcher" }); // in allowedAgents
Defensive patterns

Strategy: validation

Validate before calling

const policy = resolveSpawnPolicy(session.getSessionSpawns());
if (!policy.enabled || (policy.allowedAgents !== null && !policy.allowedAgents.includes(agentName))) {
  throw new Error(`Agent "${agentName}" not permitted; allowed: ${policy.allowedErrorText}`);
}
await task({ agent: agentName });

Try / catch

try {
  await task(req);
} catch (e) {
  if (e instanceof StructuredSubagentError && e.message.includes("Allowed:")) {
    const allowed = e.message.split("Allowed:")[1].trim();
    return task({ ...req, agent: allowed.split(", ")[0] });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling the task tool with an agentName not in the session's spawn allowlist, or when session spawns are disabled entirely (`spawnPolicy.enabled === false`).

Common situations: A restricted/embedded session configured with a limited set of spawnable agents; typo in the agent name relative to the allowlist; session spawned with `allowedAgents` narrowed by a parent tool call and the child requesting something outside it.

Related errors


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