CloakHQ/CloakBrowser · error · Error

CloakBrowser — Pre-built binaries are currently only availab

Error message

CloakBrowser — Pre-built binaries are currently only available for: ${available}.

To use CloakBrowser now, set CLOAKBROWSER_BINARY_PATH to a local Chromium binary.

What it means

StealthEvaluationError('<viewport>') is raised in human_scroll_into_view when reading the live window dimensions via world.evaluate(_VIEWPORT_JS) throws. On no_viewport (headed) launches this is the only way to get viewport geometry, and the library refuses any main-world fallback to stay undetected, so a failing isolated-world evaluate surfaces directly.

Source

Thrown at js/src/config.ts:146

export function getBinaryPath(version?: string, pro = false): string {
  const binaryDir = getBinaryDir(version, pro);
  if (process.platform === "darwin") {
    return path.join(binaryDir, "Chromium.app", "Contents", "MacOS", "Chromium");
  }
  if (process.platform === "win32") {
    return path.join(binaryDir, "chrome.exe");
  }
  return path.join(binaryDir, "chrome");
}

export function checkPlatformAvailable(): void {
  if (getLocalBinaryOverride()) return;

  const tag = getPlatformTag(); // throws if unsupported entirely
  if (!AVAILABLE_PLATFORMS.has(tag)) {
    const available = [...AVAILABLE_PLATFORMS].sort().join(", ");
    throw new Error(
      `CloakBrowser — Pre-built binaries are currently only available for: ${available}.\n\n` +
        `To use CloakBrowser now, set CLOAKBROWSER_BINARY_PATH to a local Chromium binary.`
    );
  }
}

// ---------------------------------------------------------------------------
// Download URL
// ---------------------------------------------------------------------------
export const DOWNLOAD_BASE_URL =
  process.env.CLOAKBROWSER_DOWNLOAD_URL ||
  "https://cloakbrowser.dev";

export const GITHUB_API_URL =
  "https://api.github.com/repos/CloakHQ/cloakbrowser/releases";

export const GITHUB_DOWNLOAD_BASE_URL =
  "https://github.com/CloakHQ/cloakbrowser/releases/download";

View on GitHub (pinned to d6bad5de26)

Solutions

  1. Wait for a stable state (load_state / networkidle or a known selector) before scrolling in no_viewport headed sessions.
  2. Guard with page.is_closed() and a not-None _stealth_world check immediately before the call.
  3. Pass an explicit viewport at launch so the _VIEWPORT_JS path is skipped entirely.
  4. Retry once after a short sleep — transient context teardown is common.

Example fix

// before
# headed, no_viewport launch
human_scroll_into_view(page, sel, get_box, cfg)

// after
page.wait_for_load_state("domcontentloaded")
if getattr(page, "_stealth_world", None) is not None and not page.is_closed():
    human_scroll_into_view(page, sel, get_box, cfg)
Defensive patterns

Strategy: retry

Validate before calling

if not page.is_closed() and getattr(page, "_stealth_world", None) is not None:
    vp = page._stealth_world.evaluate(_VIEWPORT_JS)
    assert isinstance(vp, dict) and vp.get('height')

Type guard

def viewport_readable(page) -> bool:
    return (not page.is_closed()) and getattr(page, "_stealth_world", None) is not None

Try / catch

try:
    human_scroll_into_view(page, sel, get_box, cfg)
except StealthEvaluationError as e:
    if '<viewport>' not in str(e): raise
    page.wait_for_load_state('domcontentloaded')
    human_scroll_into_view(page, sel, get_box, cfg)

Prevention

When it happens

Trigger: Headed launch with no_viewport plus a page that is navigating, being closed, or has a crashed/torn-down isolated world at the moment world.evaluate(_VIEWPORT_JS) runs inside human_scroll_into_view.

Common situations: Scrolling during or immediately after navigation-triggering clicks in headed mode; race between page.close() and scroll; obfuscated pages that destroy execution contexts; CDP session interruption in remote/browserstack runs.

Related errors


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