CloakHQ/CloakBrowser · error · StealthEvaluationError
Isolated-world DOM evaluation failed for "<scroll-state>"
Error message
Isolated-world DOM evaluation failed for "<scroll-state>"
What it means
After successfully evaluating the scroll-state script in the isolated world, readScrollState validates the returned shape: it must be an object with numeric y and maxY (from { y: window.scrollY, maxY: scrollHeight - clientHeight }). If the payload fails that validation (or the evaluate result is falsy), this error is thrown, indicating the document didn't yield usable scroll metrics.
Source
Thrown at js/src/human/scroll.ts:55
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;
let sent = 0;
while (sent < absD) {
const stepSize = rand(20, 40);
const chunk = Math.min(stepSize, absD - sent);
await raw.wheel(0, Math.round(chunk) * sign);
sent += chunk;
await sleep(rand(8, 20));View on GitHub (pinned to d6bad5de26)
Solutions
- Wait for a real document: await page.waitForLoadState('domcontentloaded') (or 'load') before the human action.
- Ensure the target URL actually loaded (check page.url() for chrome-error:// or about:blank after failed navigations).
- If operating on special documents, scroll explicitly on the target element (locator.scrollIntoViewIfNeeded) instead of the humanized page-level scroll path.
- Verify no page.route/content interception is replacing the document with non-HTML content.
Example fix
// before
await page.goto(url); // navigation may have failed silently
await scrollToElement(page, raw, 'text=Next');
// after
await page.goto(url, { waitUntil: 'domcontentloaded' });
if (page.url().startsWith('chrome-error')) throw new Error('nav failed');
await scrollToElement(page, raw, 'text=Next'); Defensive patterns
Strategy: validation
Validate before calling
await page.waitForLoadState('domcontentloaded');
if (/^(about:blank|chrome-error)/.test(page.url())) throw new Error('No usable document');
await scrollToElement(page, raw, selector); Type guard
function isUsableScrollState(s: unknown): s is { y: number; maxY: number } {
return !!s && typeof s === 'object' &&
typeof (s as any).y === 'number' && typeof (s as any).maxY === 'number';
} Try / catch
try {
await scrollToElement(page, raw, selector);
} catch (e) {
if (e instanceof StealthEvaluationError && e.message.includes('<scroll-state>')) {
await page.locator(selector).scrollIntoViewIfNeeded(); // non-humanized fallback
} else throw e;
} Prevention
- Never run humanized scroll on about:blank or error pages — assert page.url() first.
- Wait for domcontentloaded before scroll-dependent actions.
- Route/assert navigations so failed loads surface before the action.
When it happens
Trigger: world.evaluate(SCROLL_JS) resolves but returns null/undefined or an object where y or maxY is not a number — typically on exotic documents (e.g. an XML document, about:blank, a page whose scrollingElement/documentElement produce undefined metrics), or when serialization drops the fields.
Common situations: Calling humanized scroll/click on about:blank, the chrome-error page after a failed navigation, an iframe-less SVG/XML document, or before DOMContentLoaded when documentElement metrics are not yet numeric.
Related errors
- Invalid browser version pin. Use a full numeric Chromium ver
- Humanized DOM read requires an active isolated world
- Pro download completed but binary not found at: ${getBinaryP
- 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/e53264c3ac885290.
Report an issue: GitHub.