{"record":{"id":"2dc96af061a105bf","repo":"can1357/oh-my-pi","slug":"tab-waitfor-json-stringify-selector-timed-out","errorCode":null,"errorMessage":"tab.waitFor(${JSON.stringify(selector)}) timed out after ${timeoutMs}ms","messagePattern":"tab\\.waitFor\\((.+?)\\) timed out after (.+?)ms","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/browser/cmux/cmux-tab.ts","lineNumber":993,"sourceCode":"\t\t})()`;\n\t\tconst result = (await this.#request(\"browser.eval\", { script }, this.#runContext?.timeoutMs)) as CmuxEvalResult;\n\t\treturn result.value as TResult;\n\t}\n\n\tasync #waitForSelector(selector: string, timeoutMs: number): Promise<void> {\n\t\tconst signal = this.#runContext?.signal;\n\t\tconst spec = this.#selectorSpec(selector);\n\t\tconst nativeSelector = this.#nativeSelector(spec);\n\t\tif (nativeSelector) {\n\t\t\tawait this.#request(\"browser.wait\", { selector: nativeSelector, timeout_ms: timeoutMs }, timeoutMs, signal);\n\t\t\treturn;\n\t\t}\n\t\tconst deadline = Date.now() + timeoutMs;\n\t\twhile (Date.now() <= deadline) {\n\t\t\tif (await this.#selectorExists(spec)) return;\n\t\t\tawait untilAborted(signal, () => Bun.sleep(100));\n\t\t}\n\t\tthrow new ToolError(`tab.waitFor(${JSON.stringify(selector)}) timed out after ${timeoutMs}ms`);\n\t}\n\n\tasync #selectorExists(spec: SelectorSpec): Promise<boolean> {\n\t\tif (spec.kind === \"ref\") return this.#elementRefs.has(Number(spec.value));\n\t\tconst script = `(() => {\n\t\t\tconst spec = ${JSON.stringify(spec)};\n\t\t\t${PAGE_SELECTOR_HELPERS}\n\t\t\treturn !!findElement(spec);\n\t\t})()`;\n\t\treturn !!(await this.#evalScript<unknown>(script));\n\t}\n\n\tasync #selectorBox(spec: SelectorSpec): Promise<BoundingBox | null> {\n\t\tif (spec.kind === \"ref\") return null;\n\t\tconst script = `(() => {\n\t\t\tconst spec = ${JSON.stringify(spec)};\n\t\t\t${PAGE_SELECTOR_HELPERS}\n\t\t\tconst element = findElement(spec);","sourceCodeStart":975,"sourceCodeEnd":1011,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/browser/cmux/cmux-tab.ts#L975-L1011","documentation":"`tab.waitFor(selector)` polls `#selectorExists` every 100ms until a deadline (`Date.now() + timeoutMs`); if the selector never resolves to an existing element/ref in time, it throws this ToolError naming the selector and the elapsed timeout. It is the element-wait timeout for the cmux tab facade.","triggerScenarios":"Waiting for an element that never appears: wrong selector, element rendered only after an action you didn't perform, SPA route not navigated, or a timeoutMs shorter than the page's actual render time.","commonSituations":"Slow network or API causing late render; selector written for a different page version; waiting for content behind login/auth that redirected away; using a CSS selector where the spec expects a different kind (text/ref).","solutions":["Increase the timeoutMs to cover the page's worst-case render time, or verify the element actually exists with tab.evaluate.","Fix the selector: test it directly in the page (document.querySelector) and prefer stable ids/data attributes.","Ensure any prerequisite action (login, navigation, click that triggers render) happens before waitFor."],"exampleFix":"// before\nawait tab.waitFor('.results-row', { timeoutMs: 2000 });\n// after\nawait tab.waitFor('.results-row', { timeoutMs: 15000 }); // slow API renders in ~5-8s","handlingStrategy":"retry","validationCode":"const exists = await tab.evaluate(`!!document.querySelector(${JSON.stringify(sel)})`);\nif (!exists) console.warn('waitFor: selector not in DOM yet:', sel);","typeGuard":null,"tryCatchPattern":"try {\n  await tab.waitFor(sel, { timeoutMs: 15000 });\n} catch (err) {\n  if (String(err.message).includes('timed out after')) {\n    // retry once with longer budget after checking page state\n    await tab.waitFor(sel, { timeoutMs: 30000 });\n  } else throw err;\n}","preventionTips":["Budget timeouts for worst-case render time, not happy-path.","Perform prerequisite actions (login, navigate, trigger) before waitFor.","Prefer stable selectors (ids, data-test attributes) and verify them in DevTools first."],"tags":["timeout","selector","browser-automation","waiting"],"backgroundTag":"wait-for-selector-timeout","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}