{"record":{"id":"0b9fbd0ab61bdf7c","repo":"santifer/career-ops","slug":"the-apply-feature-needs-google-chrome-install-chr","errorCode":null,"errorMessage":"The apply feature needs Google Chrome. Install Chrome (or run: npx playwright install chromium) and try again.","messagePattern":"The apply feature needs Google Chrome\\. Install Chrome \\(or run: npx playwright install chromium\\) and try again\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"web/src/lib/apply/session.ts","lineNumber":141,"sourceCode":"const SESSIONS: Map<string, Session> = (globalThis.__coApplySessions ??= new Map());\n\nasync function headedBrowser(): Promise<Browser> {\n  const b = globalThis.__coHeadedBrowser;\n  if (b && b.isConnected()) return b;\n  let nb: Browser;\n  try {\n    nb = await chromium.launch({\n      channel: \"chrome\",\n      headless: false,\n      args: [\"--window-position=-3200,-3200\", \"--window-size=1280,940\"], // off-screen during fill; moved on-screen at handoff\n    });\n  } catch {\n    // No system Google Chrome → fall back to Playwright's bundled Chromium if\n    // present; otherwise a clear, actionable error.\n    try {\n      nb = await chromium.launch({ headless: false, args: [\"--window-position=-3200,-3200\", \"--window-size=1280,940\"] });\n    } catch {\n      throw new Error(\"The apply feature needs Google Chrome. Install Chrome (or run: npx playwright install chromium) and try again.\");\n    }\n  }\n  globalThis.__coHeadedBrowser = nb;\n  return nb;\n}\n\n/** Close the headed Chrome once no sessions have been active for a while, so we\n *  don't leak a browser process. Re-armed on every prune/close; cancelled on open. */\nfunction scheduleIdleClose() {\n  if (globalThis.__coIdleTimer) clearTimeout(globalThis.__coIdleTimer);\n  globalThis.__coIdleTimer = setTimeout(() => {\n    if (SESSIONS.size === 0) {\n      const b = globalThis.__coHeadedBrowser;\n      globalThis.__coHeadedBrowser = undefined;\n      void b?.close().catch(() => {});\n    }\n  }, 5 * 60_000);\n}","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/web/src/lib/apply/session.ts#L123-L159","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before — no browser bootstrap in setup\nnpm install\n// after — fetch the browser as part of setup\nnpm install && npx playwright install chromium && npx playwright install-deps chromium","handlingStrategy":"validation","validationCode":"// Run during install / boot, before openSession is reachable.\nimport { chromium } from 'playwright';\nasync function canLaunchHeaded() {\n  for (const opts of [\n    { channel: 'chrome', headless: false },\n    { headless: false }, // bundled chromium\n  ]) {\n    try {\n      const b = await chromium.launch(opts);\n      await b.close();\n      return true;\n    } catch {}\n  }\n  return false;\n}\nif (!await canLaunchHeaded()) {\n  console.error('Run: npx playwright install chromium  (and install-deps on Linux)');\n  process.exit(1);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const { id } = await openSession(url);\n} catch (e) {\n  if (/needs Google Chrome/.test(e.message)) {\n    // surface install instructions to the user; do NOT auto-retry the same launch\n    throw new Error('Browser missing. Run `npx playwright install chromium` then retry.');\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["playwright","browser","environment","setup","apply"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}