santifer/career-ops · critical · Error
The apply feature needs Google Chrome. Install Chrome (or ru
Error message
The apply feature needs Google Chrome. Install Chrome (or run: npx playwright install chromium) and try again.
What it means
Thrown when the headed-browser bootstrap in session.ts cannot launch ANY usable Chromium-based browser. The code first tries Google Chrome via Playwright's `channel: 'chrome'` launch; on failure it retries with Playwright's bundled Chromium (no channel). Only if BOTH launches fail does it throw, because the apply feature genuinely requires a headed browser to drive a real form. This is a hard environment prerequisite, not a transient runtime fault.
Source
Thrown at web/src/lib/apply/session.ts:141
const SESSIONS: Map<string, Session> = (globalThis.__coApplySessions ??= new Map());
async function headedBrowser(): Promise<Browser> {
const b = globalThis.__coHeadedBrowser;
if (b && b.isConnected()) return b;
let nb: Browser;
try {
nb = await chromium.launch({
channel: "chrome",
headless: false,
args: ["--window-position=-3200,-3200", "--window-size=1280,940"], // off-screen during fill; moved on-screen at handoff
});
} catch {
// No system Google Chrome → fall back to Playwright's bundled Chromium if
// present; otherwise a clear, actionable error.
try {
nb = await chromium.launch({ headless: false, args: ["--window-position=-3200,-3200", "--window-size=1280,940"] });
} catch {
throw new Error("The apply feature needs Google Chrome. Install Chrome (or run: npx playwright install chromium) and try again.");
}
}
globalThis.__coHeadedBrowser = nb;
return nb;
}
/** Close the headed Chrome once no sessions have been active for a while, so we
* don't leak a browser process. Re-armed on every prune/close; cancelled on open. */
function scheduleIdleClose() {
if (globalThis.__coIdleTimer) clearTimeout(globalThis.__coIdleTimer);
globalThis.__coIdleTimer = setTimeout(() => {
if (SESSIONS.size === 0) {
const b = globalThis.__coHeadedBrowser;
globalThis.__coHeadedBrowser = undefined;
void b?.close().catch(() => {});
}
}, 5 * 60_000);
}View on GitHub (pinned to 9b17a8ac97)
Solutions
- Run `npx playwright install chromium` in the project root to fetch Playwright's bundled Chromium (no system Chrome needed).
- Install Google Chrome system-wide (Debian/Ubuntu: `wget` the .deb + `sudo apt install ./google-chrome-stable_current_amd64.deb`; macOS: download from google.com/chrome).
- On Linux, also install Playwright's system deps: `npx playwright install-deps chromium` (libnss3, libatk1.0, libgbm, etc.).
- Verify the install with `npx playwright --version` and a smoke test (`npx playwright open about:blank`) before retrying `openSession`.
- In headless CI where the feature is unsupported, skip the apply route or gate it behind an env check rather than retrying the same launch.
Example fix
// before — no browser bootstrap in setup npm install // after — fetch the browser as part of setup npm install && npx playwright install chromium && npx playwright install-deps chromium
Defensive patterns
Strategy: validation
Validate before calling
// Run during install / boot, before openSession is reachable.
import { chromium } from 'playwright';
async function canLaunchHeaded() {
for (const opts of [
{ channel: 'chrome', headless: false },
{ headless: false }, // bundled chromium
]) {
try {
const b = await chromium.launch(opts);
await b.close();
return true;
} catch {}
}
return false;
}
if (!await canLaunchHeaded()) {
console.error('Run: npx playwright install chromium (and install-deps on Linux)');
process.exit(1);
} Try / catch
try {
const { id } = await openSession(url);
} catch (e) {
if (/needs Google Chrome/.test(e.message)) {
// surface install instructions to the user; do NOT auto-retry the same launch
throw new Error('Browser missing. Run `npx playwright install chromium` then retry.');
}
throw e;
} Prevention
- Run `npx playwright install chromium` as a documented setup step (postinstall script or onboarding).
- Add a browser-presence check to your smoke test / CI before any apply-route test runs.
- On Linux CI, also run `npx playwright install-deps chromium` for system libraries.
- Gate the apply UI behind a feature flag that's off until a browser is confirmed present.
When it happens
Trigger: Calling `openSession()` (which calls `headedBrowser()`) on a machine where (a) Google Chrome is not installed AND (b) Playwright's bundled Chromium has not been downloaded via `npx playwright install chromium`. A second `chromium.launch()` with no channel fails (e.g. `Error: browserType.launch: Executable doesn't exist`), pushing execution into the inner catch where this Error is constructed.
Common situations: Fresh CI/container/VM with Node installed but no browser; first run after cloning on a new OS; Docker image missing Chrome; `npx playwright install` skipped in setup docs; Chrome uninstalled or moved; Linux server without GUI libs (libnss3, libatk, etc.) where even bundled Chromium can't start.
Related errors
- ${msg}
- apply session not found (it may have expired)
- apply session not found
- Could not determine the rendered PDF page count (received ${
- Could not determine the rendered PDF page count from its pag
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/0b9fbd0ab61bdf7c.
Report an issue: GitHub.