{"record":{"id":"1be41eb24037bc3b","repo":"can1357/oh-my-pi","slug":"subagent-isolation-apply-and-merge-controls-are","errorCode":null,"errorMessage":"Subagent isolation, apply, and merge controls are unavailable in plan mode.","messagePattern":"Subagent isolation, apply, and merge controls are unavailable in plan mode\\.","errorType":"validation","errorClass":"StructuredSubagentError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/task/structured-subagent.ts","lineNumber":208,"sourceCode":"function createPlanModeAgent(agent: AgentDefinition): AgentDefinition {\n\tconst tools = [...PLAN_MODE_TOOLS, ...(agent.tools ?? []).filter(tool => tool === \"ast_grep\")];\n\treturn {\n\t\t...agent,\n\t\tsystemPrompt: `${planModeSubagentPrompt}\\n\\n${agent.systemPrompt}`,\n\t\ttools,\n\t\tspawns: undefined,\n\t\tprewalk: undefined,\n\t};\n}\n\nfunction assertPlanControlsAllowed(request: StructuredSubagentRequest, planMode: boolean): void {\n\tif (!planMode) return;\n\tconst isolation = request.isolation;\n\tif (\n\t\tisolation &&\n\t\t(Object.hasOwn(isolation, \"requested\") || Object.hasOwn(isolation, \"apply\") || Object.hasOwn(isolation, \"merge\"))\n\t) {\n\t\tthrow new StructuredSubagentError(\n\t\t\t\"preflight\",\n\t\t\t\"Subagent isolation, apply, and merge controls are unavailable in plan mode.\",\n\t\t);\n\t}\n}\n\nfunction 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(","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/task/structured-subagent.ts#L190-L226","documentation":"This error is thrown during subagent preflight when a structured subagent request includes isolation controls (requested/apply/merge on the `isolation` object) while the session is in plan mode. Plan mode is read-only by design: spawning agents that create worktrees, apply changes, or merge results would violate it. `assertPlanControlsAllowed` (via `resolveEffectiveSubagentPolicy`) rejects any isolation object that sets any of those keys before the agent is spawned.","triggerScenarios":"Calling the structured subagent (task tool) with `isolation: { requested: true }` (or `apply`/`merge` set, even to false via Object.hasOwn presence check) while the parent session is in plan mode.","commonSituations":"A main-agent prompt template that always attaches isolation options now running under plan mode; a user toggles plan mode mid-session and re-runs a previously valid task call; programmatic SDK callers reusing a request builder that hardcodes isolation settings.","solutions":["Remove the `isolation` field (or the requested/apply/merge keys) from the subagent request while in plan mode","Exit plan mode (accept the plan) before spawning an isolated subagent","Guard the call site: only pass isolation controls when `session` is not in plan mode"],"exampleFix":"// before\nawait task({ agent: \"researcher\", isolation: { requested: true } });\n// after\nawait task({ agent: \"researcher\" }); // plan mode: no isolation controls","handlingStrategy":"validation","validationCode":"if (sessionPlanMode && request.isolation && (\"requested\" in request.isolation || \"apply\" in request.isolation || \"merge\" in request.isolation)) {\n  throw new Error(\"Cannot use isolation controls in plan mode\");\n}\nawait task(request);","typeGuard":null,"tryCatchPattern":"try {\n  await task(req);\n} catch (e) {\n  if (e instanceof StructuredSubagentError && e.stage === \"preflight\" && e.message.includes(\"plan mode\")) {\n    const { isolation, ...rest } = req;\n    return task(rest); // retry without isolation\n  }\n  throw e;\n}","preventionTips":["Only attach isolation options when the session is in execution mode","Centralize subagent request construction so plan-mode calls cannot include isolation","Test plan-mode paths of any workflow that spawns subagents"],"tags":["subagent","plan-mode","isolation","preflight"],"backgroundTag":"feature-disabled-in-mode","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}