CloakHQ/CloakBrowser · error · UnsupportedHumanizeSelectorError
Humanized selector ${selector} is not supported by the isola
Error message
Humanized selector ${selector} is not supported by the isolated-world resolver. Supported: CSS, text=, xpath=, getByTestId, getByPlaceholder, getByAltText, getByTitle, getByText, getByLabel, and a trailing .first()/.nth()/.last(). Not supported: getByRole, chained locators (a >> b, .filter(), .and(), .or()), frameLocator, :visible and :nth-match. Use a CSS or text= selector for this action, or humanize:false to fall back to Playwright. What it means
The humanized (isolated-world) resolver only understands a subset of selector syntax: plain CSS, text=, xpath=, getByTestId/Placeholder/AltText/Title/Text/Label pseudo-locators, and a single trailing .first()/.nth()/.last(). When buildSnapshotJs runs the selector in the stealth world it returns an UNSUPPORTED status, and selectorSnapshot maps that to this error. It exists because the isolated-world resolver is a deliberately small JS evaluator that cannot parse Playwright's full locator engine (getByRole, chaining, filters, frameLocator, engine pseudo-selectors).
Source
Thrown at js/src/human/index.ts:181
x = 0;
y = 0;
initialized = false;
}
// ============================================================================
// Canonical selector snapshot — isolated world only
// ============================================================================
async function selectorSnapshot(
stealth: StealthEval | null,
selector: string,
): Promise<SnapshotPayload> {
if (!stealth) throw new StealthWorldUnavailableError();
const { status, data } = await evalParsed(stealth, buildSnapshotJs(selector));
if (status === OK && data) return data as SnapshotPayload;
if (status === NOT_FOUND) throw new ElementNotAttachedError(selector);
if (status === UNSUPPORTED) throw new UnsupportedHumanizeSelectorError(selector);
throw new StealthEvaluationError(selector);
}
// ============================================================================
// Page-level patching
// ============================================================================
/**
* Replace page methods with human-like implementations.
*/
function patchPage(page: Page, cfg: HumanConfig, cursor: CursorState): void {
const originals = {
click: page.click.bind(page),
dblclick: page.dblclick.bind(page),
hover: page.hover.bind(page),
type: page.type.bind(page),
fill: page.fill.bind(page),View on GitHub (pinned to d6bad5de26)
Solutions
- Replace the locator with a plain CSS selector or text= selector for this action (e.g. 'button#submit' or 'text=Sign in').
- Use a supported pseudo-locator such as getByTestId('submit') or getByText('Sign in') with at most one trailing .first()/.nth(i)/.last().
- Pass humanize:false (or the equivalent option) on this call to fall back to normal Playwright locator resolution.
- Restructure chained locators (a >> b, .filter(), .and(), .or()) into a single more specific CSS/text selector, and resolve frame context in your own code instead of frameLocator.
Example fix
// before
await page.getByRole('button', { name: 'Sign in' }).humanPress('Enter');
// or: await page.locator('a >> text=Sign in').humanClick();
// after
await humanPress(page, 'text=Sign in', 'Enter');
// or pass humanize:false to fall back to Playwright's engine
await page.locator('button[name="signin"]').click({ humanize: false }); Defensive patterns
Strategy: validation
Validate before calling
import { isHumanizableSelector } from './human/selector';
if (!isHumanizableSelector(selector)) {
// use a supported form or fall back to plain Playwright
await page.locator(selector).click();
} else {
await humanClick(page, selector);
} Type guard
function isHumanizableSelector(sel: string): boolean {
const supported = /^(?:[a-zA-Z[#.]\/][\s\S]*|text=|xpath=\/\/|getBy(TestId|Placeholder|AltText|Title|Text|Label)\()/;
if (/getByRole|>>|\.filter\(|\.and\(|\.or\(|frameLocator|:visible|:nth-match/.test(sel)) return false;
return supported.test(sel);
} Try / catch
try {
await humanPress(page, selector, 'Enter');
} catch (e) {
if (e instanceof UnsupportedHumanizeSelectorError) {
await page.locator(selector).press('Enter'); // humanize:false fallback
} else throw e;
} Prevention
- Standardize on CSS or text= selectors for humanized actions in your page objects.
- Lint test code for getByRole/chained locators passed into humanized helpers.
- Keep a thin wrapper that catches UnsupportedHumanizeSelectorError and retries with humanize:false.
When it happens
Trigger: Calling humanClear(), humanPress(), pressSequentially(), isChecked/checked, or isInput (anything routed through selectorSnapshot) with a selector like getByRole('button'), 'a >> text=Sign in', locator.filter({...}), .and()/.or(), a frameLocator-prefixed selector, ':visible', or ':nth-match'.
Common situations: Copy-pasting selectors from existing Playwright tests into humanized action calls; upgrading to a version where humanize:true became the default; using codegen-generated getByRole locators with the humanizer enabled.
Related errors
- Humanized DOM read requires an active isolated world
- UnsupportedHumanizeSelectorError: {selector}
- Invalid browser version pin. Use a full numeric Chromium ver
- Isolated-world DOM evaluation failed for ${selector}
- Humanized selector ${selector} is not supported by the isola
AI-assisted analysis of CloakHQ/CloakBrowser@d6bad5de26 (2026-08-28).
Data as JSON: /api/errors/139accd99c4a86a9.
Report an issue: GitHub.