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
Humanized scrolling needs to read window.scrollY and the document's scroll metrics from inside the isolated (stealth) world via getWorld(page).evaluate. If no world is registered on the page (getWorld returns undefined), readScrollState throws this error before attempting any evaluation. It signals the humanizer was used on a page where its isolated world was never installed.
Source
Thrown at js/src/human/scroll.ts:48
function isInViewport(
bounds: ElementBounds,
viewportHeight: number,
cfg: HumanConfig,
): boolean {
const topEdge = bounds.y;
const bottomEdge = bounds.y + bounds.height;
const zoneTop = viewportHeight * cfg.scroll_target_zone[0];
const zoneBottom = viewportHeight * cfg.scroll_target_zone[1];
return topEdge >= zoneTop && bottomEdge <= zoneBottom;
}
const SCROLL_JS =
'(() => { const e = document.scrollingElement || document.documentElement;' +
' return { y: window.scrollY, maxY: Math.max(0, e.scrollHeight - e.clientHeight) }; })()';
async function readScrollState(page: Page): Promise<{ y: number; maxY: number }> {
const world = getWorld(page);
if (!world) throw new StealthWorldUnavailableError();
try {
const state = await world.evaluate(SCROLL_JS);
if (
!state || typeof state !== 'object' ||
typeof state.y !== 'number' || typeof state.maxY !== 'number'
) {
throw new StealthEvaluationError('<scroll-state>');
}
return state;
} catch (error) {
if (error instanceof StealthEvaluationError) throw error;
throw new StealthEvaluationError('<scroll-state>');
}
}
async function smoothWheel(raw: RawMouse, delta: number, cfg: HumanConfig): Promise<void> {
const absD = Math.abs(delta);
const sign = delta > 0 ? 1 : -1;View on GitHub (pinned to d6bad5de26)
Solutions
- Create the page through the library's provided API (browser.newPage wrapper / withStealth / init call) so the isolated world is injected.
- Ensure humanized scroll-dependent actions are only used while the page/context the world was installed on is still open.
- Re-initialize the world on the current page with the library's setup function before calling human actions.
- If you don't need humanization for this action, call the plain Playwright scrollIntoView/click instead.
Example fix
// before const page = await context.newPage(); // no isolated world installed await scrollToElement(page, raw, 'text=Footer'); // after const page = await openHumanPage(browser); // library wrapper that installs the world await scrollToElement(page, raw, 'text=Footer');
Defensive patterns
Strategy: validation
Validate before calling
import { getWorld } from './human/world';
if (!getWorld(page)) throw new Error('Open the page via openHumanPage() before humanized actions');
await scrollToElement(page, raw, selector); Type guard
import { getWorld } from './human/world';
function hasHumanWorld(page: Page): boolean {
return getWorld(page) !== undefined;
} Try / catch
try {
await scrollToElement(page, raw, selector);
} catch (e) {
if (e instanceof StealthWorldUnavailableError) {
const page2 = await openHumanPage(browser); // re-create with world
await scrollToElement(page2, raw, selector);
} else throw e;
} Prevention
- Always create pages through the library's wrapper, never raw context.newPage().
- Set an explicit fixture/beforeEach that installs the world on every new page.
- Never call humanized APIs after context.close() or world teardown.
When it happens
Trigger: Calling scrollToElement, scrollByHuman, or any humanized action that scrolls (click/press paths calling readScrollState) on a Page that was not set up with the stealth/isolated-world injection (e.g. a plain page.create() without the library's page patching, or after the world was torn down).
Common situations: Creating pages manually instead of through the library's browser wrapper; using humanized APIs after context.close()/world cleanup; running against a remotely connected browser (playwright.chromium.connectTo) where the injection step was skipped; version upgrade changing how pages get patched.
Related errors
- Invalid browser version pin. Use a full numeric Chromium ver
- Humanized selector ${selector} is not supported by the isola
- Isolated-world DOM evaluation failed for "<scroll-state>"
- Pro download completed but binary not found at: ${getBinaryP
- Isolated-world DOM evaluation failed for ${selector}
AI-assisted analysis of CloakHQ/CloakBrowser@d6bad5de26 (2026-08-28).
Data as JSON: /api/errors/91f49a679b7c84e8.
Report an issue: GitHub.