{"record":{"id":"e53264c3ac885290","repo":"CloakHQ/CloakBrowser","slug":"isolated-world-dom-evaluation-failed-for-scroll","errorCode":null,"errorMessage":"Isolated-world DOM evaluation failed for \"<scroll-state>\"","messagePattern":"Isolated-world DOM evaluation failed for \"<scroll-state>\"","errorType":"exception","errorClass":"StealthEvaluationError","httpStatus":null,"severity":"error","filePath":"js/src/human/scroll.ts","lineNumber":55,"sourceCode":"  const zoneTop = viewportHeight * cfg.scroll_target_zone[0];\n  const zoneBottom = viewportHeight * cfg.scroll_target_zone[1];\n  return topEdge >= zoneTop && bottomEdge <= zoneBottom;\n}\n\nconst SCROLL_JS =\n  '(() => { const e = document.scrollingElement || document.documentElement;' +\n  ' return { y: window.scrollY, maxY: Math.max(0, e.scrollHeight - e.clientHeight) }; })()';\n\nasync function readScrollState(page: Page): Promise<{ y: number; maxY: number }> {\n  const world = getWorld(page);\n  if (!world) throw new StealthWorldUnavailableError();\n  try {\n    const state = await world.evaluate(SCROLL_JS);\n    if (\n      !state || typeof state !== 'object' ||\n      typeof state.y !== 'number' || typeof state.maxY !== 'number'\n    ) {\n      throw new StealthEvaluationError('<scroll-state>');\n    }\n    return state;\n  } catch (error) {\n    if (error instanceof StealthEvaluationError) throw error;\n    throw new StealthEvaluationError('<scroll-state>');\n  }\n}\n\nasync function smoothWheel(raw: RawMouse, delta: number, cfg: HumanConfig): Promise<void> {\n  const absD = Math.abs(delta);\n  const sign = delta > 0 ? 1 : -1;\n  let sent = 0;\n  while (sent < absD) {\n    const stepSize = rand(20, 40);\n    const chunk = Math.min(stepSize, absD - sent);\n    await raw.wheel(0, Math.round(chunk) * sign);\n    sent += chunk;\n    await sleep(rand(8, 20));","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/CloakHQ/CloakBrowser/blob/d6bad5de261bedf025280ace1d14e800aee13923/js/src/human/scroll.ts#L37-L73","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait page.goto(url); // navigation may have failed silently\nawait scrollToElement(page, raw, 'text=Next');\n\n// after\nawait page.goto(url, { waitUntil: 'domcontentloaded' });\nif (page.url().startsWith('chrome-error')) throw new Error('nav failed');\nawait scrollToElement(page, raw, 'text=Next');","handlingStrategy":"validation","validationCode":"await page.waitForLoadState('domcontentloaded');\nif (/^(about:blank|chrome-error)/.test(page.url())) throw new Error('No usable document');\nawait scrollToElement(page, raw, selector);","typeGuard":"function isUsableScrollState(s: unknown): s is { y: number; maxY: number } {\n  return !!s && typeof s === 'object' &&\n    typeof (s as any).y === 'number' && typeof (s as any).maxY === 'number';\n}","tryCatchPattern":"try {\n  await scrollToElement(page, raw, selector);\n} catch (e) {\n  if (e instanceof StealthEvaluationError && e.message.includes('<scroll-state>')) {\n    await page.locator(selector).scrollIntoViewIfNeeded(); // non-humanized fallback\n  } else throw e;\n}","preventionTips":["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."],"tags":["playwright","scroll","validation","isolated-world","page-state"],"backgroundTag":"unexpected-evaluation-result-shape","analyzedSha":"d6bad5de261bedf025280ace1d14e800aee13923","analyzedAt":"2026-08-28T14:13:12.918Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}