{"record":{"id":"de19cfead6021221","repo":"CloakHQ/CloakBrowser","slug":"cloakbrowser-binary-path-set-to-localoverride","errorCode":null,"errorMessage":"CLOAKBROWSER_BINARY_PATH set to '${localOverride}' but file does not exist","messagePattern":"CLOAKBROWSER_BINARY_PATH set to '(.+?)' but file does not exist","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"js/src/download.ts","lineNumber":85,"sourceCode":"\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Ensure the stealth Chromium binary is available. Download if needed.\n * Returns the path to the chrome executable.\n */\nexport async function ensureBinary(\n  licenseKey?: string,\n  browserVersion?: string,\n  releaseChannel?: string,\n): Promise<string> {\n  // Check for local override\n  const localOverride = getLocalBinaryOverride();\n  if (localOverride) {\n    if (!fs.existsSync(localOverride)) {\n      throw new Error(\n        `CLOAKBROWSER_BINARY_PATH set to '${localOverride}' but file does not exist`\n      );\n    }\n    console.log(`[cloakbrowser] Using local binary override: ${localOverride}`);\n    return localOverride;\n  }\n\n  const requestedVersion = normalizeRequestedVersion(browserVersion);\n\n  // Pro license key check (custom download URL overrides Pro path)\n  const key = resolveLicenseKey(licenseKey);\n  const effectiveKey = process.env.CLOAKBROWSER_DOWNLOAD_URL ? undefined : key;\n  if (effectiveKey) {\n    const info = await validateLicense(effectiveKey);\n    if (info?.valid) {\n      // Free tier always gets the latest build. Drop any version pin: the server\n      // force-serves latest to free keys, so fetching a pinned version's signed\n      // manifest would mismatch the served bytes and fail checksum verification.","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/CloakHQ/CloakBrowser/blob/d6bad5de261bedf025280ace1d14e800aee13923/js/src/download.ts#L67-L103","documentation":"RuntimeError('Viewport size not available') is raised in human_scroll_into_view when the resolved viewport dict is falsy or lacks a 'height' key — e.g. _VIEWPORT_JS returned an empty/None result, or the caller-supplied viewport was {'width': 0} or None. The scroller cannot compute geometry without a viewport height, so it aborts rather than guess.","triggerScenarios":"world.evaluate(_VIEWPORT_JS) returning None/{} (window.tears down mid-read, unusual embedded webviews), or page.viewport_size returning a dict without height; also passing viewport={} explicitly.","commonSituations":"Embedded/minimal browser shells (webview, old headless shell) where innerWidth/innerHeight are 0; popup windows opened with window.open before layout; pages in about:blank; races right after navigation where layout is not yet computed.","solutions":["Wait until the page has laid out (domcontentloaded plus a real document, not about:blank) before scrolling.","Launch with an explicit viewport so the value comes from Playwright configuration, not runtime reads.","Debug what _VIEWPORT_JS returns: run page._stealth_world.evaluate(_VIEWPORT_JS) and confirm {'width','height'} are non-zero; if zero, the environment itself lacks a layout viewport.","Retry once after a short delay for layout races."],"exampleFix":"// before\npage.goto('about:blank')\nhuman_scroll_into_view(page, sel, get_box, cfg)\n\n// after\npage.goto('https://example.com')\npage.wait_for_load_state('domcontentloaded')\nhuman_scroll_into_view(page, sel, get_box, cfg)","handlingStrategy":"validation","validationCode":"vp = page.viewport_size or (page._stealth_world.evaluate(_VIEWPORT_JS) if getattr(page, '_stealth_world', None) else None)\nif not vp or not vp.get('height'):\n    raise RuntimeError('viewport not measurable; wait for layout')","typeGuard":"def has_viewport(page) -> bool:\n    vp = page.viewport_size\n    return bool(vp and vp.get('height'))","tryCatchPattern":"try:\n    human_scroll_into_view(page, sel, get_box, cfg)\nexcept RuntimeError as e:\n    if 'Viewport size not available' not in str(e): raise\n    page.wait_for_load_state('domcontentloaded')\n    human_scroll_into_view(page, sel, get_box, cfg)","preventionTips":["Never scroll on about:blank or pre-layout pages","Set an explicit viewport at launch","Avoid embedded webview shells without layout viewports"],"tags":["viewport","geometry","scroll","layout"],"backgroundTag":"element-geometry-unavailable","analyzedSha":"d6bad5de261bedf025280ace1d14e800aee13923","analyzedAt":"2026-08-28T14:13:12.918Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}