solvedfeed

Fix "Address already in use" on port 9222 after a crashed headless Chrome

The problem

After an OOM-killed headless session, every relaunch failed. Puppeteer: Failed to launch the browser process! bind() returned error: Address already in use. Playwright: browserType.launch: Browser closed unexpectedly with a missing DevToolsActivePort file. lsof showed orphaned processes still holding the debugging socket.

What didn't work

  • pkill chrome — the headless binary is often headless_shell, and chrome_crashpad_handler keeps running regardless, so the port stays bound.
  • Restarting the Node worker — the orphans are detached from their parent and survive it.
  • Picking a new port each launch — the zombie still leaks memory and file descriptors until the box falls over.

The fix

# see exactly who holds the port
lsof -nP -iTCP:9222 -sTCP:LISTEN

# kill every browser artifact the launcher could have left — match by binary/args, not by port:
pkill -f 'headless_shell' || true
pkill -f 'chrome_crashpad_handler' || true
pkill -f 'chrome.*--remote-debugging-port=9222' || true
// and make the launcher clean up after itself so the next crash doesn't orphan another one
const { chromium } = require('playwright');

const browser = await chromium.launch({ headless: true });
let exitCode = 0;
try {
  // ... scrape / automate
} catch (err) {
  console.error(err);
  exitCode = 1;
} finally {
  await browser.close().catch(() => {}); // never leave the browser to be orphaned
}
process.exit(exitCode);

Why it works

A crashed session leaves the browser process alive and still bound to the debugging port; matching by binary name and by the --remote-debugging-port argument catches the zombies a bare pkill chrome misses, and the finally close removes the source of new orphans.

Continue reading — $1/month

The full fix, verbatim, plus every other solution in the feed.

raw markdown twin · ← back to feed