can1357/oh-my-pi · error · ToolError

Computer session is closed

Error message

Computer session is closed

What it means

ComputerSupervisor.run() rejects any execution request once the supervisor has been closed (this.#closed). After close(), the worker is torn down and no further code can be executed in the computer session; reusing the closed supervisor throws this ToolError instead of hanging.

Source

Thrown at packages/coding-agent/src/tools/computer/supervisor.ts:176

		},
	) {
		this.#session = session;
		this.#createWorker = createWorker;
		this.#timeouts = timeouts;
		this.#callSessionTool = callSessionTool;
	}

	async capabilities(): Promise<DesktopCapabilities | undefined> {
		return this.#latestCapabilities;
	}

	async run(
		code: string,
		timeoutMs: number,
		snapshot: ComputerSessionSnapshot,
		signal?: AbortSignal,
	): Promise<ComputerRunOk> {
		if (this.#closed) throw new ToolError("Computer session is closed");
		if (signal?.aborted) throw new ToolAbortError();
		await this.#start();
		if (signal?.aborted) throw new ToolAbortError();

		const id = `computer-${++this.#nextId}`;
		const { promise, resolve, reject } = Promise.withResolvers<ComputerRunOk>();
		const pending: PendingRun = { resolve, reject, signal, toolCalls: new Map() };
		this.#pending.set(id, pending);
		const abort = (): void => {
			this.#safeSend({ type: "abort", id });
			for (const controller of pending.toolCalls.values()) controller.abort(signal?.reason);
		};
		if (signal?.aborted) abort();
		else signal?.addEventListener("abort", abort, { once: true });

		try {
			this.#worker?.send({ type: "run", id, code, timeoutMs, session: snapshot });
			return await this.#raceWithGrace(promise, timeoutMs);

View on GitHub (pinned to 9690622007)

Solutions

  1. Create a new computer session (new supervisor) for post-close work.
  2. Guard call sites: check an isClosed/closed flag or lifecycle state before calling run().
  3. Cancel or drain pending tasks during shutdown so no run() is invoked after close().

Example fix

// before
await supervisor.close();
await supervisor.run(code, timeout, snapshot); // throws

// after
await supervisor.close();
const fresh = new ComputerSupervisor(session);
await fresh.run(code, timeout, snapshot);
Defensive patterns

Strategy: validation

Validate before calling

// track close state in your wrapper
if (supervisorClosed) {
  supervisor = new ComputerSupervisor(session); // recreate before running
}

Try / catch

try {
  await supervisor.run(code, timeout, snapshot, signal);
} catch (err) {
  if (err instanceof ToolError && err.message === "Computer session is closed") {
    supervisor = new ComputerSupervisor(session); // recreate and retry once
    return await supervisor.run(code, timeout, snapshot, signal);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling run() on a ComputerSupervisor after close()/dispose was called, or after the computer tool finished and closed the session, then issuing another run.

Common situations: A queued or retried run lands after session teardown; an agent issues a follow-up computer command after the tool reported completion; a long-lived supervisor reference is reused across requests after shutdown.

Related errors


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