can1357/oh-my-pi · warning · Error

Collab replica activation was cancelled

Error message

Collab replica activation was cancelled

What it means

After downloading the host's snapshot and writing it to a replica session file, the guest resumes it via ctx.session.switchSession(replicaPath, { preserveLocalCwd: true }). switchSession returned false, meaning the interactive session refused/aborted the switch (typically the user cancelled a confirmation prompt). The guest throws so the join is not half-applied: no snapshot state, UI, or agent mirror is adopted.

Source

Thrown at packages/coding-agent/src/collab/guest.ts:444

			this.#armSnapshotProgressTimer();
		}
		return complete;
	}

	/** Write the accumulated welcome snapshot to the replica file and (re)load it through the resume machinery. */
	async #finalizeSnapshot(): Promise<void> {
		const pending = this.#pendingSnapshot;
		this.#pendingSnapshot = null;
		this.#clearSnapshotProgressTimer();
		if (!pending || this.#left) return;
		const replicaPath = path.join(getConfigRootDir(), "collab", `${this.#roomId}.jsonl`);
		const lines = [pending.header, ...pending.entries].map(entry => JSON.stringify(entry)).join("\n");
		await Bun.write(replicaPath, `${lines}\n`);

		// Resume through AgentSession without adopting the host's cwd.
		const switched = await this.#ctx.session.switchSession(replicaPath, { preserveLocalCwd: true });
		if (switched === false) {
			throw new Error("Collab replica activation was cancelled");
		}
		this.#clearTransientUi();
		this.#clearAgentMirror();
		this.state = pending.state;
		reconcileGuestSnapshotHostState(this.#ctx, pending.state.isStreaming);
		this.#applyHostState(pending.state);
		this.#ctx.resetObserverRegistry();
		this.#applyAgentSnapshots(pending.agents);
		this.#ctx.syncRunningSubagentBadge();
		this.#assistantStreamSynced = false;
		setSessionTerminalTitle(pending.state.sessionName ?? pending.header.title, pending.state.cwd);
		this.#ctx.chatContainer.disposeChildren();
		await this.#ctx.renderInitialMessages({ clearTerminalHistory: true });
		await this.#ctx.reloadTodos();
		this.#updateStatusSegment();
		this.#readOnly = pending.readOnly;
		this.#welcomed = true;
		const suffix = this.#readOnly ? " (read-only)" : "";

View on GitHub (pinned to 9690622007)

Solutions

  1. Retry the join and accept the session-switch prompt when it appears.
  2. Finish or abandon the current session first, then re-join the room so no confirmation is needed.
  3. Inspect the replica session file written to the temp/replica path if the switch keeps failing despite accepting the prompt.
  4. If embedding the guest non-interactively, provide a switchSession implementation that does not require user confirmation, or handle the cancelled case by keeping the local session.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await guest.join(link);
} catch (err) {
  if (err instanceof Error && err.message.includes("cancelled")) {
    ui.info("Join aborted — the session switch was cancelled; current session unchanged.");
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: A guest joining a room when the interactive session prompts to switch away from the current session and the user dismisses/cancels it; switchSession failing internally and reporting false (e.g. replica file rejected by the session loader).

Common situations: Guest already has an active session with unsaved context and cancels the 'switch session?' dialog during join; a corrupted replica file causes the session manager to bail; joining from a context (RPC mode, script) where interactive switching is not possible.

Related errors


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