fix(browser): guard Playwright pageError undefined-location crash (CC-161) - #56
Merged
Merged
Conversation
…-161) Playwright 1.60's vendored Node driver reads pageError.location.url unconditionally. Firefox/Camoufox can emit a page error with no location (cross-origin "Script error.", CSP, uncaught errors) -- LinkedIn does this -- and the unguarded read throws a synchronous TypeError that kills the whole driver process. Every subsequent call then returns "Connection closed while reading from the driver": the true root cause behind the CC-141/CC-160 driver deaths. A relaunched LinkedIn scrape re-crashes on the same pageError, so those tickets' survive-and-relaunch loop can never complete a LinkedIn scrape. Fix: scripts/patch_playwright_pageerror.py surgically guards the two vendored crash sites (dispatcher + trace-event writer) with optional chaining and a null default, preserving normal pageerror behaviour when location is present. The patch is idempotent, shape-matched (fails loudly if upstream code changes), and repeatable after every uv sync / reinstall. The Dockerfile runs it after the final uv sync so the built agents image carries the guard. Verified the upstream guard (microsoft/playwright#41629) is unreleased: both 1.60.0 and 1.61.0 still ship the unguarded read. camoufox's juggler-side fix (daijro/camoufox#625) is likewise unreleased on PyPI (latest 0.4.11). So the local patch is the only fix that keeps Camoufox stealth today -- a version bump does not resolve it. Tests: tests/test_playwright_pageerror_patch.py (6) -- shape match, both crash sites, idempotency, loud-fail on unknown shape, and the installed bundle carries the guard. Full agents suite 503 passed, ruff clean on changed files.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
CC-161 — the disease behind CC-141 / CC-160 driver deaths
Playwright 1.60's vendored Node driver (
coreBundle.js) readspageError.location.urlunconditionally. Firefox/Camoufox can emit a page error with nolocation(cross-origin "Script error.", CSP, some uncaught errors). LinkedIn triggers it deterministically; jobright.ai never does. The unguarded read throws a synchronousTypeError: Cannot read properties of undefined (reading 'url')in the Node event loop → the whole driver process exits → every subsequent call returns "Connection closed while reading from the driver" (the CC-141/160 "driver death"). CC-141/160 made the crash survivable but a relaunched LinkedIn scrape re-crashes on the same pageError, so LinkedIn never completes headed. This stops the crash.Approach: A (surgical local patch) — verified, not assumed
Option B (Playwright bump) was verified infeasible: I installed and inspected the bundles — both 1.60.0 AND 1.61.0 still ship the unguarded read (the upstream guard, microsoft/playwright#41629, is unreleased). camoufox's own juggler-side fix (daijro/camoufox#625) is unreleased on PyPI (latest camoufox is 0.4.11, our pinned version, which lacks it). So a version bump does not fix the crash today, and Option A is the only fix that keeps Camoufox stealth.
scripts/patch_playwright_pageerror.py— guards the two vendored crash sites (thePageErrordispatcher + the_onPageErrortrace-event writer) withpageError.location?.url ?? null(+ line/column). Idempotent, shape-matched (fails loudly if upstream shape changes), repeatable after everyuv sync/ reinstall. Normal pageerror behaviour preserved whenlocationis present (optional chaining short-circuits only on nullish).Dockerfile— runs the patch after the finaluv syncso the built agents image carries the guard.tests/test_playwright_pageerror_patch.py— 6 tests: shape match, both crash sites, idempotency, loud-fail on unknown shape, and an assertion that the installed bundle carries the guard.Local-dev wiring note
Local dev must run
uv run python scripts/patch_playwright_pageerror.pyafteruv sync(and afterpython -m camoufox fetchreinstalls). The Dockerfile hook is in this repo (agents-owned). The parent'smake/compose that drive localuv syncmay want the same post-sync call — flagging for cc-orchestrator to decide if a parent-side Makefile hook is warranted (this PR does not touch parent).Test results
tests/test_playwright_pageerror_patch.py— 6 passed.tools/discover_sites.pysyntax errors are unrelated and untouched.)Build-don't-ship; no parent pin bump (Doug-gated). No graph structure change → no
graph_static.jsonregen.🤖 Generated with Claude Code