can1357/oh-my-pi · error

ACP session fork failed: ${params.sessionId}

Error message

ACP session fork failed: ${params.sessionId}

What it means

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.

Source

Thrown at packages/coding-agent/src/modes/acp/acp-agent.ts:1287

		}
		return await this.#openStoredSession(storedSession.path, cwd, mcpServers, sessionId);
	}

	async #forkManagedSession(params: ForkSessionRequest): Promise<ManagedSessionRecord> {
		const sourcePath = await this.#resolveForkSourceSessionPath(params.sessionId);
		const { session, setToolUIContext } = normalizeCreatedAcpSession(
			await this.#createSession(path.resolve(params.cwd), {
				interactivePrompts: this.#clientCapabilities?.elicitation?.form != null,
			}),
		);
		try {
			const success = await session.switchSession(sourcePath);
			if (!success) {
				throw new Error(`ACP session fork was cancelled: ${params.sessionId}`);
			}
			const forked = await session.fork();
			if (!forked) {
				throw new Error(`ACP session fork failed: ${params.sessionId}`);
			}
		} catch (error) {
			await this.#disposeStandaloneSession(session);
			throw error;
		}
		return await this.#registerPreparedSession(session, params.mcpServers ?? [], setToolUIContext);
	}

	async #openStoredSession(
		sessionPath: string,
		cwd: string,
		mcpServers: McpServer[],
		sessionId: string,
	): Promise<ManagedSessionRecord> {
		const { session, setToolUIContext } = normalizeCreatedAcpSession(
			await this.#createSession(path.resolve(cwd), {
				interactivePrompts: this.#clientCapabilities?.elicitation?.form != null,
			}),

View on GitHub (pinned to 9690622007)

Solutions

  1. Check extensions for `session_before_switch` handlers that cancel reason "fork" and allow it instead.
  2. Verify the session is persisting (session file exists via sessionManager.getSessionFile()) before requesting a fork.
  3. Retry the fork with extensions disabled to isolate the veto.

Example fix

// before: hook blanket-cancels
if (event.reason === "fork") return { cancel: true };
// after: only cancel for protected sessions
if (event.reason === "fork" && isProtectedSession(event)) return { cancel: true };
return { cancel: false };
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure the source session is persisting before fork
const sessionFile = session.sessionManager.getSessionFile();
if (!sessionFile) throw new Error("session is not persisted; fork unavailable");

Try / catch

try {
  await agent.fork({ sessionId });
} catch (err) {
  if (err.message.includes("fork failed")) {
    // fork vetoed by hook or session not persisting; check extensions and persistence
  }
  throw err;
}

Prevention

When it happens

Trigger: 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).

Common situations: Extensions that veto fork operations; sessions opened without persistence; regression after upgrading where session files stopped being created before fork.

Related errors


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