heygen-com/hyperframes · error · Error

[BrowserManager] Chrome binary not found at HYPERFRAMES_BROW

Error message

[BrowserManager] Chrome binary not found at HYPERFRAMES_BROWSER_PATH="${envPath}". Run `hyperframes browser ensure` to re-download.

What it means

Thrown by resolveHeadlessShellPath() when the HYPERFRAMES_BROWSER_PATH environment variable is set to a path that does not exist on disk. This is the third priority in the resolution chain (after config.chromePath and PRODUCER_HEADLESS_SHELL_PATH). Like the other env-var checks, a set-but-missing path throws rather than silently falling through, because an explicit override should be respected or corrected.

Source

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

  config?: Partial<Pick<EngineConfig, "chromePath">>,
): string | undefined {
  if (config?.chromePath) {
    return config.chromePath;
  }
  if (process.env.PRODUCER_HEADLESS_SHELL_PATH) {
    const envPath = process.env.PRODUCER_HEADLESS_SHELL_PATH;
    if (!existsSync(envPath)) {
      throw new Error(
        `[BrowserManager] Chrome binary not found at PRODUCER_HEADLESS_SHELL_PATH="${envPath}". ` +
          "Run `hyperframes browser ensure` to re-download.",
      );
    }
    return envPath;
  }
  if (process.env.HYPERFRAMES_BROWSER_PATH) {
    const envPath = process.env.HYPERFRAMES_BROWSER_PATH;
    if (!existsSync(envPath)) {
      throw new Error(
        `[BrowserManager] Chrome binary not found at HYPERFRAMES_BROWSER_PATH="${envPath}". ` +
          "Run `hyperframes browser ensure` to re-download.",
      );
    }
    return envPath;
  }
  const home = homedir();
  return (
    findCachedHeadlessShell(
      join(home, ".cache", "hyperframes", "chrome", "chrome-headless-shell"),
    ) ?? findCachedHeadlessShell(join(home, ".cache", "puppeteer", "chrome-headless-shell"))
  );
}

// Preserve the producer-era export so re-export shims keep the same public API.
export const ENABLE_BROWSER_POOL = DEFAULT_CONFIG.enableBrowserPool;

// Flags only meaningful when Chrome's compositor is driven by

View on GitHub (pinned to c2996c8626)

Solutions

  1. Run hyperframes browser ensure to re-download the managed Chrome headless shell.
  2. Verify or unset: ls -la $HYPERFRAMES_BROWSER_PATH or unset HYPERFRAMES_BROWSER_PATH.
  3. If you intentionally set this for a system Chrome install, reinstall Chrome or update the path.
  4. Use config.chromePath in code/config instead of env vars for reproducible team setups.

Example fix

# before
export HYPERFRAMES_BROWSER_PATH=/usr/bin/google-chrome
# (Chrome uninstalled)

# after
npx hyperframes browser ensure
# or unset HYPERFRAMES_BROWSER_PATH
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from 'fs';

function validateBrowserPath(): void {
  const envPath = process.env.HYPERFRAMES_BROWSER_PATH;
  if (envPath && !existsSync(envPath)) {
    console.warn(`HYPERFRAMES_BROWSER_PATH points to missing file: ${envPath}. Unsetting.`);
    delete process.env.HYPERFRAMES_BROWSER_PATH;
  }
}

Try / catch

try {
  resolveHeadlessShellPath(config);
} catch (err) {
  if (err instanceof Error && err.message.includes('HYPERFRAMES_BROWSER_PATH')) {
    delete process.env.HYPERFRAMES_BROWSER_PATH;
    resolveHeadlessShellPath(config);
  }
  throw err;
}

Prevention

When it happens

Trigger: resolveHeadlessShellPath() reaches the HYPERFRAMES_BROWSER_PATH branch (config.chromePath is unset, PRODUCER_HEADLESS_SHELL_PATH is unset or resolved already). The env var is non-empty, existsSync fails on its value, and the error fires.

Common situations: HYPERFRAMES_BROWSER_PATH was set for a local dev machine but the project was moved or Chrome was updated/removed. CI inherited the env var from a different runner image. A teammate's shell profile exports it globally.

Related errors


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