CloakHQ/CloakBrowser · error · Error

Viewport size not available

Error message

Viewport size not available

What it means

humanScrollIntoView could not obtain a usable viewport: page.viewport() returned null and the in-page window.innerWidth/innerHeight evaluation returned a falsy height. Scrolling math needs viewport height, so it aborts.

Source

Thrown at js/src/human-puppeteer/scroll.ts:105

 */
export async function humanScrollIntoView(
  page: Page,
  raw: RawMouse,
  getBox: () => Promise<ElementBounds | null>,
  cursorX: number,
  cursorY: number,
  cfg: HumanConfig,
): Promise<{ box: ElementBounds; cursorX: number; cursorY: number }> {
  // Headed launches default to null defaultViewport so the page tracks the real
  // OS window; page.viewport() is then null. Fall back to the live window
  // dimensions so humanize works headed (the stealth-relevant mode).
  let viewport = page.viewport();
  if (!viewport) {
    viewport = await page.evaluate(
      () => ({ width: window.innerWidth, height: window.innerHeight }),
    );
  }
  if (!viewport || !viewport.height) throw new Error('Viewport size not available');

  let box = await getBox();
  if (!box) throw new Error('Element not found while scrolling into view');

  if (isInViewport(box, viewport.height, cfg)) {
    return { box, cursorX, cursorY };
  }

  // Move cursor into scroll area
  const scrollAreaX = Math.round(viewport.width * rand(0.3, 0.7));
  const scrollAreaY = Math.round(viewport.height * rand(0.3, 0.7));
  await humanMove(raw, cursorX, cursorY, scrollAreaX, scrollAreaY, cfg);
  cursorX = scrollAreaX;
  cursorY = scrollAreaY;
  await sleep(randRange(cfg.scroll_pre_move_delay));

  // Calculate scroll distance
  const targetY = viewport.height * rand(cfg.scroll_target_zone[0], cfg.scroll_target_zone[1]);

View on GitHub (pinned to d6bad5de26)

Solutions

  1. Ensure the page is fully open and not navigating before calling humanScrollIntoView
  2. Set an explicit viewport when creating the page/browser context (page.setViewport or defaultViewport)
  3. Await pending navigations (page.waitForNavigation / networkidle) before scrolling
  4. Guard with a page.isClosed() check and skip/retry the scroll

Example fix

// before
await humanScrollIntoView(page, selector);

// after
if (page.isClosed()) throw new Error('page closed');
await page.setViewport({ width: 1280, height: 800 });
await humanScrollIntoView(page, selector);
Defensive patterns

Strategy: validation

Validate before calling

async function ensureViewport(page: Page): Promise<void> {
  if (page.isClosed()) throw new Error('page closed');
  if (!page.viewport()) await page.setViewport({ width: 1280, height: 800 });
}

Type guard

function isViewportUnavailable(e: unknown): e is Error {
  return e instanceof Error && e.message === 'Viewport size not available';
}

Try / catch

try { await humanScrollIntoView(page, sel); }
catch (e) { if (isViewportUnavailable(e)) { await page.setViewport({width:1280,height:800}); await humanScrollIntoView(page, sel); } else throw e; }

Prevention

When it happens

Trigger: Calling humanScrollIntoView on a page that is closing/closed, a page in an odd headless mode where viewport is unset and window dimensions are 0, or when page.evaluate fails silently returning undefined.

Common situations: Browser context torn down concurrently (navigation/close race), zero-sized headless viewport configuration, or calling scroll helpers after page.close() began.

Related errors


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