← Back to microsoft/playwright
microsoft / playwright · Issue No. 42153
makeSocketPath(domain, name) (packages/playwright-core/src/server/utils/fileUtils.ts; observed in vendored @playwright/cli 0.1.6 → lib/coreBundle.js:7903-7912) composes os.tmpdir()/pw-<userhash8>/<domain>/<name>.sock with no length guard. For the cli domain, daemonSocketPath() (src/tools/cli-daemon/daemon.ts; lib/coreBundle.js:64634-64636) passes name = <workspaceDirHash16>-<sessionName>. On macOS the default $TMPDIR is /var/folders/xx/…/T (~48 bytes), giving a ~65-byte prefix, and sockaddr_un.sun_path is 104 bytes — so any session name longer than ~17 characters overflows.
libuv silently truncates the path on BOTH bind() and connect() (reproduced on Node 22.10.0 / libuv 1.49.2), so the socket is created at the truncated path and the session initially works. But fs.stat()/fs.unlink() use the untruncated path, so all three cleanup paths miss the file that actually exists:
startCliDaemonServer()'s socketExists + unlink stale-socket guard (daemon.ts; coreBundle.js:64557-64563) never fires → server.listen() throws EADDRINUSE;deleteSessionFile()'s unlink(sessionConfig.socketPath) (coreBundle.js:64614-64616) never removes the socket — and swallows the ENOENT;Session._connect()'s error-path unlink (src/tools/cli-client/session.ts; lib/tools/cli-client/session.js:112-118) never removes it either.Consequences: after any abrupt daemon exit — including playwright-cli kill-all, which SIGKILLs (lib/tools/cli-client/program.js:241) so libuv never unlinks — the socket file survives forever. open -s=<same name> throws Error: listen EADDRINUSE …/<full-name>.sock, printing a path that is not on disk (the on-disk name is truncated and has no .sock suffix), and every later command reports "The browser is not open". Only a manual rm of the truncated path recovers. Two session names sharing a truncated prefix also silently collide on one socket.
Repro (macOS):
S=$(uuidgen)
playwright-cli -s=$S open https://example.com
ls -l "$TMPDIR"/pw-*/cli/ # name is truncated, .sock suffix gone
playwright-cli kill-all
playwright-cli -s=$S open https://example.com # EADDRINUSE on a path ls cannot find
Suggested fix: in makeSocketPath, when the composed path would exceed sizeof(sun_path) (104 darwin / 108 linux), substitute a digest for the name — e.g. <sha1(name).slice(0,16)>.sock — so the on-disk name stays deterministic and bounded; or throw a clear error naming the limit rather than letting the kernel truncate. Secondary: have startCliDaemonServer catch EADDRINUSE and print an actionable message (with the real on-disk path) instead of a raw Node stack.
Context: we drive playwright-cli from coding agents with per-project session names (UUIDs); this footgun cost multiple debugging sessions before the truncation was spotted.
Relay reads this issue against the repository's contribution signals: the files it is likely to touch, how the maintainers triage work this size, and what the first contribution would exercise.
The full analysis for this issue is still being assembled. Until then, the description above and the thread on GitHub are the most reliable context.