{"record":{"id":"40172809ee676945","repo":"can1357/oh-my-pi","slug":"acp-session-fork-failed-params-sessionid","errorCode":null,"errorMessage":"ACP session fork failed: ${params.sessionId}","messagePattern":"ACP session fork failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/modes/acp/acp-agent.ts","lineNumber":1287,"sourceCode":"\t\t}\n\t\treturn await this.#openStoredSession(storedSession.path, cwd, mcpServers, sessionId);\n\t}\n\n\tasync #forkManagedSession(params: ForkSessionRequest): Promise<ManagedSessionRecord> {\n\t\tconst sourcePath = await this.#resolveForkSourceSessionPath(params.sessionId);\n\t\tconst { session, setToolUIContext } = normalizeCreatedAcpSession(\n\t\t\tawait this.#createSession(path.resolve(params.cwd), {\n\t\t\t\tinteractivePrompts: this.#clientCapabilities?.elicitation?.form != null,\n\t\t\t}),\n\t\t);\n\t\ttry {\n\t\t\tconst success = await session.switchSession(sourcePath);\n\t\t\tif (!success) {\n\t\t\t\tthrow new Error(`ACP session fork was cancelled: ${params.sessionId}`);\n\t\t\t}\n\t\t\tconst forked = await session.fork();\n\t\t\tif (!forked) {\n\t\t\t\tthrow new Error(`ACP session fork failed: ${params.sessionId}`);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tawait this.#disposeStandaloneSession(session);\n\t\t\tthrow error;\n\t\t}\n\t\treturn await this.#registerPreparedSession(session, params.mcpServers ?? [], setToolUIContext);\n\t}\n\n\tasync #openStoredSession(\n\t\tsessionPath: string,\n\t\tcwd: string,\n\t\tmcpServers: McpServer[],\n\t\tsessionId: string,\n\t): Promise<ManagedSessionRecord> {\n\t\tconst { session, setToolUIContext } = normalizeCreatedAcpSession(\n\t\t\tawait this.#createSession(path.resolve(cwd), {\n\t\t\t\tinteractivePrompts: this.#clientCapabilities?.elicitation?.form != null,\n\t\t\t}),","sourceCodeStart":1269,"sourceCodeEnd":1305,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/modes/acp/acp-agent.ts#L1269-L1305","documentation":"Thrown by AcpAgent's fork handling when session.fork() returns false. AgentSession.fork() returns false when a `session_before_switch` extension hook (reason \"fork\") cancels the fork, or when the session is not persisting to disk. The provisional session is disposed and the fork request fails.","triggerScenarios":"An ACP session/fork request reaches the fork() step but either an extension hook returns { cancel: true } for reason \"fork\", or the new session has no session file backing (persistence disabled/not yet created).","commonSituations":"Extensions that veto fork operations; sessions opened without persistence; regression after upgrading where session files stopped being created before fork.","solutions":["Check extensions for `session_before_switch` handlers that cancel reason \"fork\" and allow it instead.","Verify the session is persisting (session file exists via sessionManager.getSessionFile()) before requesting a fork.","Retry the fork with extensions disabled to isolate the veto."],"exampleFix":"// before: hook blanket-cancels\nif (event.reason === \"fork\") return { cancel: true };\n// after: only cancel for protected sessions\nif (event.reason === \"fork\" && isProtectedSession(event)) return { cancel: true };\nreturn { cancel: false };","handlingStrategy":"try-catch","validationCode":"// ensure the source session is persisting before fork\nconst sessionFile = session.sessionManager.getSessionFile();\nif (!sessionFile) throw new Error(\"session is not persisted; fork unavailable\");","typeGuard":null,"tryCatchPattern":"try {\n  await agent.fork({ sessionId });\n} catch (err) {\n  if (err.message.includes(\"fork failed\")) {\n    // fork vetoed by hook or session not persisting; check extensions and persistence\n  }\n  throw err;\n}","preventionTips":["Verify session persistence is enabled and a session file exists before forking.","Do not install hooks that blanket-cancel reason \"fork\".","Retry forks with extensions disabled when diagnosing."],"tags":["acp","session-fork","cancelled-by-hook"],"backgroundTag":"operation-cancelled-by-hook","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}