{"record":{"id":"c0730259e1e2d594","repo":"can1357/oh-my-pi","slug":"operation-requires-an-active-cmux-browser-run","errorCode":null,"errorMessage":"${operation} requires an active cmux browser run","messagePattern":"(.+?) requires an active cmux browser run","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/browser/cmux/cmux-tab.ts","lineNumber":1130,"sourceCode":"\t\t}\n\t}\n\n\t#normalizeGeometry(value: unknown): CmuxGeometry {\n\t\tconst object = value && typeof value === \"object\" ? (value as Record<string, unknown>) : {};\n\t\treturn {\n\t\t\tinnerWidth: numberFrom(object.innerWidth, DEFAULT_VIEWPORT.width),\n\t\t\tinnerHeight: numberFrom(object.innerHeight, DEFAULT_VIEWPORT.height),\n\t\t\tdpr: numberFrom(object.dpr, DEFAULT_VIEWPORT.deviceScaleFactor ?? 1),\n\t\t\tscrollX: numberFrom(object.scrollX, 0),\n\t\t\tscrollY: numberFrom(object.scrollY, 0),\n\t\t\tscrollWidth: numberFrom(object.scrollWidth, DEFAULT_VIEWPORT.width),\n\t\t\tscrollHeight: numberFrom(object.scrollHeight, DEFAULT_VIEWPORT.height),\n\t\t};\n\t}\n\n\t#requireRunContext(operation: string): RunContext {\n\t\tif (!this.#runContext) {\n\t\t\tthrow new ToolError(`${operation} requires an active cmux browser run`);\n\t\t}\n\t\treturn this.#runContext;\n\t}\n}\n\nclass CmuxResponse {\n\treadonly #record: CmuxResponseRecord;\n\n\tconstructor(record: CmuxResponseRecord) {\n\t\tthis.#record = record;\n\t}\n\n\turl(): string {\n\t\treturn this.#record.url;\n\t}\n\n\tstatus(): number {\n\t\treturn this.#record.status;","sourceCodeStart":1112,"sourceCodeEnd":1148,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/browser/cmux/cmux-tab.ts#L1112-L1148","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Move the browser calls inside the active cmux browser run block so the run context is installed.","Don't cache CmuxTab/page references across runs — obtain them within each run's scope.","Guard async callbacks: check the run is still active (or abort them with the run's signal) before issuing browser calls."],"exampleFix":"// before\nconst tab = await browser.openTab();\nsetTimeout(() => tab.navigate(url), 5000); // fires after run ended\n// after\nawait withBrowserRun(async () => {\n  const tab = await browser.openTab();\n  await tab.navigate(url);\n});","handlingStrategy":"validation","validationCode":"// structure code so all browser calls live inside the run scope\nif (!runIsActive) throw new Error('browser API used outside cmux run');\nawait withBrowserRun(async (tab) => { /* all tab calls here */ });","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never retain tab/page/browser handles beyond the run's lifetime — scope them to the run callback.","Tie background async work to the run's AbortSignal and cancel it in finally.","Funnel all browser access through a helper that asserts the run context exists."],"tags":["lifecycle","browser-automation","state-error","run-context"],"backgroundTag":"no-active-session","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}