pa11y worker crashed running axe on spa route - how to fix it
TL;DR
Stabilize the SPA route before scanning: wait for hydration to finish, disable route-transition animations during scans, and run the crashing route alone with a single worker. Pa11y-ci workers die when axe runs mid-transition on a half-torn-down DOM. One line of why: axe walks the live DOM, and if the SPA swaps the route out from under it, the context axe is analyzing disappears.
The error, verbatim
Error: Worker crashed while running axe-core
at pa11y-ci (node_modules/pa11y-ci/lib/pa11y-ci.js)
url: https://example.com/app/settings
Fix it step by step
Step 1: Reproduce on the single route
npx pa11y https://example.com/app/settings --reporter json | head -10
Expected: The worker crash reproduces on this route but not on static routes.
Step 2: Check for route transition churn
npx pa11y https://example.com/app/settings --wait 5000 --reporter json | head -10
Expected: Adding a wait changes the outcome, pointing at hydration or transition timing.
Step 3: Scan with a ready selector
npx pa11y https://example.com/app/settings --wait '#app[data-hydrated=true]' --reporter cli | tail -3
Expected: Scan completes once axe runs against the settled DOM.
Step 4: Run pa11y-ci single-worker for the route
npx pa11y-ci --config .pa11yci.json --workers 1 | tail -5
Expected: The crashing route passes with one worker and a ready selector in config.
Step 5: Re-run twice to rule out flakes
npx pa11y https://example.com/ | tail -2
Expected: Two consecutive clean runs before calling it fixed; scan tools flake under load, so one green run is not proof.
When to use this skill
- The scan tool itself fails or crashes instead of reporting violations
- Your a11y CI step errors out before any rule results appear
- You run this tooling (pa11y, lighthouse, cypress-axe, axe-playwright) in automation
When NOT to use this skill
- The tool runs fine and reports real violations, use the rule-specific skills instead
- The failure is in your app code, not the scanner
Compatibility
pa11y-ci 3.x with pa11y 6.x. The --wait selector and --workers 1 flags are the stabilizers. Pin the tool version in the lockfile so scans stay reproducible across machines.
Variant phrasings
pa11y-ci worker crashed axe
Same failure, same fix.
pa11y spa route crash
Practitioner phrasing, the cause is scanning mid-hydration.
same failure locally and in CI
Scan tool failures are environmental; a fix that works on a laptop must also be verified under CI conditions.
Why it happens
Pa11y-ci fans scans out to workers, and each worker loads the URL then injects axe. On SPA routes, the DOM is still hydrating or the router is mid-transition when axe starts, and tearing down the DOM mid-analysis crashes the worker. Parallel workers make it worse by starving CPU, stretching hydration past the point axe expects. Waiting for a ready signal (a data attribute your app sets after hydration) removes the race. Scan tool failures are environmental more often than not: memory, network, certificates, and browser state. When a fix works locally, verify it under CI conditions too, because CI runners are slower, more locked down, and run things in parallel.
Edge cases
- Have the app set data-hydrated=true when rendering settles, and wait for that selector in scan config.
- Disable animations and transitions during scans via a query param or media query, they stretch the unsettled window.
- If one route always crashes, quarantine it to a single-worker run rather than destabilizing the whole batch.
- Record the working flags in CI config or a runbook; the fix evaporates if it only lives in one person's shell history.
Provenance
Resolved from the public thread: https://vectle.com/posts/pstUDNJ9cHX55HHu508MJclQ