can1357/oh-my-pi · error · ToolError

requires an active cmux browser run

Error message

${operation} requires an active cmux browser run

What it means

CmuxTab methods that need run-scoped state (abort signal, timeouts, run scope) call `#requireRunContext(operation)`, which throws this ToolError when `#runContext` is unset. Browser operations are only valid inside an active cmux browser run; calling them outside one has no execution context.

Solutions

  1. Move the browser calls inside the active cmux browser run block so the run context is installed.
  2. Don't cache CmuxTab/page references across runs — obtain them within each run's scope.
  3. Guard async callbacks: check the run is still active (or abort them with the run's signal) before issuing browser calls.

Example fix

// before
const tab = await browser.openTab();
setTimeout(() => tab.navigate(url), 5000); // fires after run ended
// after
await withBrowserRun(async () => {
  const tab = await browser.openTab();
  await tab.navigate(url);
});
Defensive patterns

Strategy: validation

Validate before calling

// structure code so all browser calls live inside the run scope
if (!runIsActive) throw new Error('browser API used outside cmux run');
await withBrowserRun(async (tab) => { /* all tab calls here */ });

Prevention

When it happens

Trigger: Invoking tab/page/browser methods (navigation, eval, screenshots, wait) before a browser run starts, after it finished/aborted, or from a detached/reused CmuxTab instance whose run ended.

Common situations: Calling the facade from test setup code outside the run helper; keeping a tab reference after the run's finally block cleared the context; async callbacks (timers, event handlers) firing after the run completed.

Related errors


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

Appendix: source

Thrown at packages/coding-agent/src/tools/browser/cmux/cmux-tab.ts:1130

		}
	}

	#normalizeGeometry(value: unknown): CmuxGeometry {
		const object = value && typeof value === "object" ? (value as Record<string, unknown>) : {};
		return {
			innerWidth: numberFrom(object.innerWidth, DEFAULT_VIEWPORT.width),
			innerHeight: numberFrom(object.innerHeight, DEFAULT_VIEWPORT.height),
			dpr: numberFrom(object.dpr, DEFAULT_VIEWPORT.deviceScaleFactor ?? 1),
			scrollX: numberFrom(object.scrollX, 0),
			scrollY: numberFrom(object.scrollY, 0),
			scrollWidth: numberFrom(object.scrollWidth, DEFAULT_VIEWPORT.width),
			scrollHeight: numberFrom(object.scrollHeight, DEFAULT_VIEWPORT.height),
		};
	}

	#requireRunContext(operation: string): RunContext {
		if (!this.#runContext) {
			throw new ToolError(`${operation} requires an active cmux browser run`);
		}
		return this.#runContext;
	}
}

class CmuxResponse {
	readonly #record: CmuxResponseRecord;

	constructor(record: CmuxResponseRecord) {
		this.#record = record;
	}

	url(): string {
		return this.#record.url;
	}

	status(): number {
		return this.#record.status;

View on GitHub (pinned to 9690622007)