{"record":{"id":"633381c22abfa7ac","repo":"can1357/oh-my-pi","slug":"cannot-spawn-agentname-allowed-spawnpolic","errorCode":null,"errorMessage":"Cannot spawn '${agentName}'. Allowed: ${spawnPolicy.allowedErrorText}","messagePattern":"Cannot spawn '(.+?)'\\. Allowed: (.+?)","errorType":"validation","errorClass":"StructuredSubagentError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/task/structured-subagent.ts","lineNumber":233,"sourceCode":"function assertDepthAndSpawnAllowed(request: StructuredSubagentRequest, agentName: string): void {\n\tconst taskDepth = request.session.taskDepth ?? 0;\n\tconst maxDepth = request.session.settings.get(\"task.maxRecursionDepth\") ?? 2;\n\tif (!canSpawnAtDepth(maxDepth, taskDepth)) {\n\t\tthrow new StructuredSubagentError(\n\t\t\t\"preflight\",\n\t\t\t`Cannot spawn another agent at task depth ${taskDepth}; maximum depth is ${maxDepth}.`,\n\t\t);\n\t}\n\tconst blockedAgent = request.blockedAgent ?? $env.PI_BLOCKED_AGENT;\n\tif (blockedAgent && blockedAgent === agentName) {\n\t\tthrow new StructuredSubagentError(\n\t\t\t\"preflight\",\n\t\t\t`Cannot spawn ${blockedAgent} agent from within itself (recursion prevention). Use a different agent type.`,\n\t\t);\n\t}\n\tconst spawnPolicy = resolveSpawnPolicy(request.session.getSessionSpawns());\n\tif (!spawnPolicy.enabled || (spawnPolicy.allowedAgents !== null && !spawnPolicy.allowedAgents.includes(agentName))) {\n\t\tthrow new StructuredSubagentError(\n\t\t\t\"preflight\",\n\t\t\t`Cannot spawn '${agentName}'. Allowed: ${spawnPolicy.allowedErrorText}`,\n\t\t);\n\t}\n}\n\n/**\n * Resolve every policy shared by task and eval before allocating artifacts or\n * dispatching work. Callers translate {@link StructuredSubagentError} into\n * their own wire-level error surface.\n */\nexport async function resolveEffectiveSubagentPolicy(\n\trequest: StructuredSubagentRequest,\n): Promise<EffectiveSubagentPolicy> {\n\tawait request.session.settings.reloadFromDisk();\n\tconst spawnPolicy = resolveSpawnPolicy(request.session.getSessionSpawns());\n\tconst agentName = request.agent?.trim() || spawnPolicy.defaultAgent;\n\tconst planMode = request.session.getPlanModeState?.()?.enabled === true;","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/task/structured-subagent.ts#L215-L251","documentation":"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`.","triggerScenarios":"Calling the task tool with an agentName not in the session's spawn allowlist, or when session spawns are disabled entirely (`spawnPolicy.enabled === false`).","commonSituations":"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.","solutions":["Request one of the agents listed in the error's `Allowed:` text","Reconfigure the session's spawn policy (getSessionSpawns / session spawn settings) to include the desired agent","Enable session spawning if `spawnPolicy.enabled` is false"],"exampleFix":"// before\nawait task({ agent: \"explorer\" }); // not allowed\n// after\nawait task({ agent: \"researcher\" }); // in allowedAgents","handlingStrategy":"validation","validationCode":"const policy = resolveSpawnPolicy(session.getSessionSpawns());\nif (!policy.enabled || (policy.allowedAgents !== null && !policy.allowedAgents.includes(agentName))) {\n  throw new Error(`Agent \"${agentName}\" not permitted; allowed: ${policy.allowedErrorText}`);\n}\nawait task({ agent: agentName });","typeGuard":null,"tryCatchPattern":"try {\n  await task(req);\n} catch (e) {\n  if (e instanceof StructuredSubagentError && e.message.includes(\"Allowed:\")) {\n    const allowed = e.message.split(\"Allowed:\")[1].trim();\n    return task({ ...req, agent: allowed.split(\", \")[0] });\n  }\n  throw e;\n}","preventionTips":["Check the session's spawn allowlist before composing agent names in prompts","Keep allowlists and prompt templates in sync","Avoid narrowing allowedAgents unless the child workflow is fully known"],"tags":["subagent","spawn-policy","allowlist","permissions"],"backgroundTag":"agent-not-in-allowlist","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}