CloakHQ/CloakBrowser · error · StealthWorldUnavailableError

Humanized DOM read requires an active isolated world

Error message

Humanized DOM read requires an active isolated world

What it means

readBox calls getWorld(pageOrFrame) to find the page's isolated (stealth) world; when it returns null the humanized geometry read cannot run and this error is thrown. It means no isolated world is currently attached to that page/frame.

Source

Thrown at js/src/human/actionability.ts:129

  const world = getWorld(pageOrFrame);
  if (!world) throw new StealthWorldUnavailableError();

  const { status, data } = await evalParsed(world, buildActionableJs(selector));
  if (status === UNSUPPORTED) throw new UnsupportedHumanizeSelectorError(selector);
  if (status === EVALUATION_FAILED) throw new StealthEvaluationError(selector);
  if (status === NOT_FOUND) throw new ElementNotAttachedError(selector);
  if (status !== OK || !data) throw new StealthEvaluationError(selector);
  if (checks.has('visible') && !data.visible) throw new ElementNotVisibleError(selector);
  if (checks.has('enabled') && !data.enabled) throw new ElementNotEnabledError(selector);
  if (checks.has('editable') && !data.editable) throw new ElementNotEditableError(selector);
}

async function readBox(
  pageOrFrame: Page | Frame,
  selector: string,
): Promise<{ x: number; y: number; width: number; height: number } | null> {
  const world = getWorld(pageOrFrame);
  if (!world) throw new StealthWorldUnavailableError();

  const { status, data } = await evalParsed(world, buildBoxJs(selector));
  if (status === OK && data?.box) return data.box;
  if (status === NOT_FOUND) return null;
  if (status === UNSUPPORTED) throw new UnsupportedHumanizeSelectorError(selector);
  throw new StealthEvaluationError(selector);
}

export async function ensureActionable(
  pageOrFrame: Page | Frame,
  selector: string,
  checks: ReadonlySet<CheckName>,
  timeout: number = 30000,
  force: boolean = false,
): Promise<void> {
  if (force) return;

  const deadline = Date.now() + timeout;

View on GitHub (pinned to d6bad5de26)

Solutions

  1. Retry after a short delay or after waitForLoadState — world injection is usually only a beat behind
  2. Ensure the page was created through this library's API so world initialization is wired up
  3. Await a sentinel proving the world binding exists before the first humanized action
  4. Fall back to humanize:false to use Playwright's native path when the world cannot be established

Example fix

// before
await page.goto(url);
await humanClick(page, '#go');
// after
await page.goto(url);
await page.waitForFunction(() => (window as any).__stealthReady === true);
await humanClick(page, '#go');
Defensive patterns

Strategy: retry

Validate before calling

try { await page.waitForFunction(() => !!(window as any).__stealthWorld, null, { timeout: 3000 }); } catch { /* fall back to humanize:false */ }

Type guard

function isStealthWorldUnavailableError(e: unknown): e is StealthWorldUnavailableError {
  return e instanceof Error && /requires an active isolated world/.test(e.message);
}

Try / catch

try { await humanClick(page, sel); } catch (e) { if (isStealthWorldUnavailableError(e)) { await page.waitForTimeout(200); await humanClick(page, sel); } else throw e; }

Prevention

When it happens

Trigger: Calling humanClick/humanHover (which read the element box via readBox) before the isolated world is initialized, after the world was torn down (navigation to a new document, context close), or on a Frame whose parent world binding hasn't propagated.

Common situations: Acting immediately after page.goto before world setup completes, running on a freshly attached iframe, browser context recreation, or a race between world injection and the first humanized action.

Related errors


AI-assisted analysis of CloakHQ/CloakBrowser@d6bad5de26 (2026-08-28). Data as JSON: /api/errors/14ec773db4d73481. Report an issue: GitHub.