can1357/oh-my-pi · error · ToolError
tab.ariaSnapshot: selector ${JSON.stringify(selector)} match
Error message
tab.ariaSnapshot: selector ${JSON.stringify(selector)} matched no element What it means
`tab.ariaSnapshot` accepts an optional selector to scope the accessibility snapshot to a subtree; when `page.$(normalizeSelector(selector))` returns null the selector matched no element and this ToolError is thrown before snapshotting. It prevents silently snapshotting the whole page when a scoping root was requested.
Source
Thrown at packages/coding-agent/src/tools/browser/tab-worker.ts:1626
`tab.goto(${JSON.stringify(url)}) timed out after ${budgetBound}ms; pending navigation stopped — retry with a longer tool timeout or waitUntil:"domcontentloaded"`,
);
}
throw err;
}
}),
observe: opts => op("tab.observe()", quickOpMs, sig => this.#collectObservation({ ...opts, signal: sig })),
ariaSnapshot: (selector, opts) =>
op(
selector ? `tab.ariaSnapshot(${JSON.stringify(selector)})` : "tab.ariaSnapshot()",
quickOpMs,
async sig => {
let root: ElementHandle | null = null;
if (selector) {
root = (await untilAborted(sig, () =>
page.$(normalizeSelector(selector)),
)) as ElementHandle | null;
if (!root)
throw new ToolError(
`tab.ariaSnapshot: selector ${JSON.stringify(selector)} matched no element`,
);
}
try {
return await untilAborted(sig, () => captureAriaSnapshot(page, root, opts));
} finally {
await root?.dispose().catch(() => undefined);
}
},
),
screenshot: opts =>
op(describeScreenshot(opts), quickOpMs, sig =>
this.#captureScreenshot(session, output, screenshots, sig, opts),
),
extract: (format = "markdown") =>
op(`tab.extract(${JSON.stringify(format)})`, quickOpMs, async sig => {
const html = (await untilAborted(sig, () => page.content())) as string;
const result = await extractReadableFromHtml(html, page.url(), format);View on GitHub (pinned to 9690622007)
Solutions
- Capture a full-page ariaSnapshot (omit the selector) to inspect actual accessible structure and fix the selector
- Wait for the element to appear before snapshotting
- Scope the selector to the right frame or use a pierce/shadow-aware selector syntax
- Verify the selector with `page.$(selector)` directly to confirm matching
Example fix
// before
const snap = await tab.ariaSnapshot({ selector: '.results-panel' }); // not rendered yet
// after
await tab.wait(() => tab.$('.results-panel'), { timeout: 5000 });
const snap = await tab.ariaSnapshot({ selector: '.results-panel' }); Defensive patterns
Strategy: validation
Validate before calling
if (!(await tab.$(selector))) {
throw new Error(`selector ${selector} not present yet`);
}
const snap = await tab.ariaSnapshot({ selector }); Try / catch
try {
return await tab.ariaSnapshot({ selector });
} catch (err) {
if (err instanceof ToolError && err.message.includes('matched no element')) {
return await tab.ariaSnapshot(); // full-page fallback
}
throw err;
} Prevention
- Wait for the element before scoping a snapshot to it
- Verify selectors with page.$ before using them as scope roots
- Use shadow-piercing or frame-scoped selectors when needed
- Capture a full-page snapshot first to discover correct accessible names/structure
When it happens
Trigger: Calling ariaSnapshot with a selector that resolves to nothing: typo, wrong frame/iframe context, element not yet rendered, or shadow-DOM piercing needed but not expressed in the selector.
Common situations: Selector written against a different DOM state (pre-render SPA, delayed hydration); CSS selector used where the page uses shadow roots; element inside an iframe not targeted; casing/attribute mismatch.
Related errors
- tab.select() requires a <select> element
- tab.waitFor(${JSON.stringify(selector)}) timed out after ${t
- Drag selector did not resolve to a visible element: ${target
- ${label} failed fast after ${afterMs}ms${formatSelectorMatch
- Selected ${sourceName} session is no longer available
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/3d220c695d128cb0.
Report an issue: GitHub.