{"record":{"id":"73c781a68f7be12d","repo":"can1357/oh-my-pi","slug":"accessibility-snapshot-unavailable","errorCode":null,"errorMessage":"Accessibility snapshot unavailable","messagePattern":"Accessibility snapshot unavailable","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/browser/tab-worker.ts","lineNumber":1847,"sourceCode":"\t\t\t},\n\t\t\tid: async id => enrich(await this.#resolveCachedHandle(id)),\n\t\t\tref: async id => enrich(await this.#resolveAriaRef(id)),\n\t\t};\n\t}\n\n\tasync #collectObservation(options: {\n\t\tincludeAll?: boolean;\n\t\tviewportOnly?: boolean;\n\t\tsignal?: AbortSignal;\n\t}): Promise<Observation> {\n\t\tconst page = this.#requirePage();\n\t\tthis.#clearElementCache();\n\t\tconst includeAll = options.includeAll ?? false;\n\t\tconst viewportOnly = options.viewportOnly ?? false;\n\t\tconst snapshot = (await untilAborted(options.signal, () =>\n\t\t\tpage.accessibility.snapshot({ interestingOnly: !includeAll }),\n\t\t)) as SerializedAXNode | null;\n\t\tif (!snapshot) throw new ToolError(\"Accessibility snapshot unavailable\");\n\t\tconst entries: ObservationEntry[] = [];\n\t\tawait collectObservationEntries(this, snapshot, entries, { includeAll, viewportOnly });\n\t\tconst scroll = (await untilAborted(options.signal, () =>\n\t\t\tpage.evaluate(() => {\n\t\t\t\tconst win = globalThis as unknown as {\n\t\t\t\t\tscrollX: number;\n\t\t\t\t\tscrollY: number;\n\t\t\t\t\tinnerWidth: number;\n\t\t\t\t\tinnerHeight: number;\n\t\t\t\t\tdocument: { documentElement: { scrollWidth: number; scrollHeight: number } };\n\t\t\t\t};\n\t\t\t\tconst doc = win.document.documentElement;\n\t\t\t\treturn {\n\t\t\t\t\tx: win.scrollX,\n\t\t\t\t\ty: win.scrollY,\n\t\t\t\t\twidth: win.innerWidth,\n\t\t\t\t\theight: win.innerHeight,\n\t\t\t\t\tscrollWidth: doc.scrollWidth,","sourceCodeStart":1829,"sourceCodeEnd":1865,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/browser/tab-worker.ts#L1829-L1865","documentation":"tab.observe()/snapshot calls page.accessibility.snapshot({ interestingOnly }) to build the element observation list. If the browser returns a null accessibility tree, the worker throws this ToolError because there is nothing to enumerate. A null tree means the page's accessibility tree could not be computed (empty/blank page, unsupported target, or the tree was disabled/being rebuilt).","triggerScenarios":"Calling tab.observe() (or any snapshot with includeAll/viewportOnly options) on a page whose accessibility snapshot returns null: a blank or about:blank tab, a crashed renderer, a page that closed mid-snapshot, or a target where Playwright/Puppeteer cannot enable the accessibility domain.","commonSituations":"Observing a tab that navigated to about:blank or an empty document; the tab was closed by the site between command dispatch and snapshot; headless browser attached to a page with accessibility tree suppressed; snapshot raced with a navigation that reset the DOM.","solutions":["Re-run the observe/snapshot after confirming the page has loaded real content (check page URL/main frame).","Retry the snapshot after a short delay — transient null trees often resolve once navigation completes.","Wait for a meaningful load state (e.g. waitForNavigation/load) before calling observe().","If the tab is dead, close it and open a fresh tab, then observe again."],"exampleFix":"// before\nconst snapshot = await page.accessibility.snapshot({ interestingOnly: true });\n// after\nawait page.waitForNavigation({ waitUntil: \"load\" }).catch(() => undefined);\nconst snapshot = await page.accessibility.snapshot({ interestingOnly: true });\nif (!snapshot) throw new Error(\"page has no accessibility tree yet — retry after load\");","handlingStrategy":"retry","validationCode":"const url = await tab.evaluate(() => location.href);\nif (!url || url === \"about:blank\") throw new Error(\"navigate to a real page before observe()\");","typeGuard":"function hasAxTree(s: unknown): s is { role: string; children?: unknown[] } {\n  return !!s && typeof s === \"object\" && \"role\" in s;\n}","tryCatchPattern":"try {\n  const obs = await tab.observe({ signal });\n} catch (err) {\n  if (err.message.includes(\"Accessibility snapshot unavailable\")) {\n    await Bun.sleep(500);\n    return retryObserve();\n  }\n  throw err;\n}","preventionTips":["Wait for page load/navigation to settle before observing","Check location.href is not about:blank before calling observe","Treat one null snapshot as transient and retry once","Keep the tab alive — avoid navigating or closing it while observing"],"tags":["browser","accessibility","snapshot","empty-state"],"backgroundTag":"accessibility-snapshot-unavailable","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}