heygen-com/hyperframes · error · Error

beginFrame screenshot returned ${bytes.length} bytes after $

Error message

beginFrame screenshot returned ${bytes.length} bytes after ${BEGINFRAME_SCREENSHOT_PROBE_ATTEMPTS} attempts with signature ${bytes.length >= 4 ? bytes.subarray(0, 4).toString("hex") : "<empty>"}

What it means

Thrown after the beginFrame screenshot probe exhausts all BEGINFRAME_SCREENSHOT_PROBE_ATTEMPTS (10) retries without obtaining a valid PNG. Each attempt calls screenshot and checks the first 4 bytes for the PNG magic number (89 50 4E 47). The error includes byte count and hex signature for diagnostics, revealing whether Chrome returned empty data, JPEG, or garbage.

Source

Thrown at packages/engine/src/services/browserManager.ts:388

        `screenshot beginFrame attempt ${attempts}`,
      );
      const screenshot = response.screenshotData ?? "";
      bytes = screenshot ? Buffer.from(screenshot, "base64") : Buffer.alloc(0);
      isPng =
        bytes.length >= 8 &&
        bytes[0] === 0x89 &&
        bytes[1] === 0x50 &&
        bytes[2] === 0x4e &&
        bytes[3] === 0x47;
      if (isPng) break;
      await awaitBeforeDeadline(
        new Promise((resolveDelay) => setTimeout(resolveDelay, 10)),
        deadline,
        `screenshot retry delay ${attempts}`,
      );
    }
    if (!isPng) {
      throw new Error(
        `beginFrame screenshot returned ${bytes.length} bytes after ` +
          `${BEGINFRAME_SCREENSHOT_PROBE_ATTEMPTS} attempts with signature ` +
          `${bytes.length >= 4 ? bytes.subarray(0, 4).toString("hex") : "<empty>"}`,
      );
    }
    await awaitBeforeDeadline(client.detach(), deadline, "CDP detach").catch(() => {});
    result = {
      supported: true,
      detail:
        `enable + warm-up + ${bytes.length}-byte PNG beginFrame succeeded ` +
        `after ${attempts} screenshot attempt(s)`,
      durationMs: Date.now() - started,
    };
  } catch (error) {
    result = {
      supported: false,
      detail: error instanceof Error ? error.message : String(error),
      durationMs: Date.now() - started,

View on GitHub (pinned to c2996c8626)

Solutions

  1. Check the hex signature in the error: '<empty>' means no data at all (beginFrame not functional); a JPEG signature means format negotiation failed.
  2. Use a standard Chrome headless shell build: run hyperframes browser ensure.
  3. If on a custom Chrome, verify it supports HeadlessExperimental.beginFrame with PNG screenshots.
  4. The probe gracefully reports supported: false on failure — ensure downstream code falls back to non-beginFrame capture.
Defensive patterns

Strategy: fallback

Try / catch

let beginFrameSupported = true;
try {
  const result = await probeBeginFrameSupport(browser);
  beginFrameSupported = result.supported;
} catch (err) {
  if (err instanceof Error && err.message.includes('beginFrame screenshot returned')) {
    beginFrameSupported = false;
  } else {
    throw err;
  }
}
// use beginFrame capture only if beginFrameSupported === true

Prevention

When it happens

Trigger: The probe loop calls client.send('Page.captureScreenshot', { format: 'png' }) up to 10 times with 10ms delays. Every result fails the PNG signature check (bytes[0]===0x89 && bytes[1]===0x50 && bytes[2]===0x4e && bytes[3]===0x47). After the last attempt, the isPng flag is still false and the error fires.

Common situations: The Chrome headless shell doesn't support beginFrame screenshot capture properly (older or stripped build). The page hasn't rendered any content yet (empty/blank screenshots). A GPU/compositing issue produces corrupted frame data. The headless shell is a non-standard build that returns JPEG or raw data instead of PNG.

Related errors


AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12). Data as JSON: /api/errors/6cc1b5f5a39f4144. Report an issue: GitHub.