can1357/oh-my-pi · error · ToolError
Unsupported selector prefix. Use CSS or puppeteer query hand
Error message
Unsupported selector prefix. Use CSS or puppeteer query handlers (aria/, text/, xpath/, pierce/). Got: ${selector} What it means
normalizeSelector rejects selectors starting with the legacy `p-` prefix unless they match a recognized legacy form. These `p-` handlers were the old puppeteer-style prefixes; unrecognized `p-...` selectors are refused with a pointer to the supported handlers (aria/, text/, xpath/, pierce/) or plain CSS.
Source
Thrown at packages/coding-agent/src/tools/browser/tab-worker.ts:290
}): Promise<HTTPResponse | null>;
id(n: number): Promise<ActionableHandle>;
ref(id: string): Promise<ActionableHandle>;
}
export function normalizeSelector(selector: string): string {
assertSelectorString(selector);
if (!selector) return selector;
if (
!SELECTOR_HANDLER_PREFIXES.some(prefix => selector.startsWith(prefix)) &&
PLAYWRIGHT_ONLY_SELECTOR_RE.test(selector)
) {
throw new ToolError(
`Playwright-only selector ${JSON.stringify(selector)} is not supported by the browser tool. ` +
`Use a puppeteer text selector ("text/Allow all"), an aria selector ("aria/Name"), CSS, or "xpath/...".`,
);
}
if (selector.startsWith("p-") && !LEGACY_SELECTOR_PREFIXES.some(prefix => selector.startsWith(prefix))) {
throw new ToolError(
`Unsupported selector prefix. Use CSS or puppeteer query handlers (aria/, text/, xpath/, pierce/). Got: ${selector}`,
);
}
if (selector.startsWith("p-text/")) return `text/${selector.slice("p-text/".length)}`;
if (selector.startsWith("p-xpath/")) return `xpath/${selector.slice("p-xpath/".length)}`;
if (selector.startsWith("p-pierce/")) return `pierce/${selector.slice("p-pierce/".length)}`;
if (selector.startsWith("p-aria/")) {
const rest = selector.slice("p-aria/".length);
const nameMatch = rest.match(/\[\s*name\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\]]+))\s*\]/);
const name = nameMatch?.[1] ?? nameMatch?.[2] ?? nameMatch?.[3];
if (name) return `aria/${name.trim()}`;
return `aria/${rest}`;
}
return selector;
}
function isInteractiveNode(node: SerializedAXNode): boolean {
if (INTERACTIVE_AX_ROLES.has(node.role)) return true;View on GitHub (pinned to 9690622007)
Solutions
- Drop the `p-` prefix: `p-aria/Name` → `aria/Name`, `p-text/...` → `text/...`.
- For text/xpath/pierce the legacy `p-` forms are auto-rewritten — use the bare form directly to avoid relying on the alias.
- Use plain CSS when no handler is needed.
- Update stored prompts/playbooks that still emit `p-` selectors.
Example fix
// before
tab.click("p-text/Allow all");
// after
tab.click("text/Allow all"); Defensive patterns
Strategy: validation
Validate before calling
if (selector.startsWith("p-")) {
selector = selector.replace(/^p-(text|xpath|pierce)\//, "$1/"); // migrate legacy prefix
} Prevention
- Drop the legacy p- prefix everywhere; use bare handler prefixes (aria/, text/, xpath/, pierce/)
- Search old scripts for 'p-' selectors and migrate them
- Rely on CSS for selectors that need no query handler
When it happens
Trigger: Passing selectors like `p-role/button`, `p-css=...`, or any `p-`-prefixed string that is not one of the migrated legacy forms (`p-text/`, `p-xpath/`, `p-pierce/`, etc.).
Common situations: Older prompts/scripts/agent traces that used the deprecated `p-` selector dialect; mixed-up prefixes like `p-aria/` after the migration renamed them to bare `aria/`.
Related errors
- Playwright-only selector ${JSON.stringify(selector)} is not
- Timed out clicking ${selector} (seen ${lastSeen} matches; la
- Selected ${sourceName} session is no longer available
- Browser selector must be a string; got ${kind}. tab.click/ty
- tab.ariaSnapshot: selector ${__sel} matched no element
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/bae56f1b03ebf8f0.
Report an issue: GitHub.