Oxide 4.3.3: Windows access violation after scanning in a Node worker and unloading the addon
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 25/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Stale
- Tech stack
- node.js
- Domain
- backend, operating-systems
Research direction
Start with the linked reproduction's compare.cjs and repro.cjs, then review draft PR #20471 and its regression fixture. Run node compare.cjs 20 on Windows to compare worker-only and retained-library behavior; done means the intermittent access violation is prevented and the retention assertion passes without regressing the documented scanner tests.
Written by the indexing model from the issue text.
Description
What version of Tailwind CSS are you using?
@tailwindcss/oxide and @tailwindcss/oxide-win32-x64-msvc 4.3.3.
What build tool (or framework if it abstracts the build tool) are you using?
The reproduction uses only Node's built-in worker_threads and Oxide. Originally encountered during Expo/Metro Android release builds using UniWind 1.11.0, but those tools are not required to reproduce it.
What version of Node.js are you using?
v24.13.1, win32 x64. The original build also failed on v24.20.0; the isolated results below are specifically from v24.13.1.
What browser are you using?
N/A.
What operating system are you using?
Windows 11 Pro, build 26200, x64. ESET remained enabled during the isolated comparison; no antivirus exclusions or diagnostic preloads were used.
Reproduction URL
https://github.com/bompus/oxide-worker-unload-repro
git clone https://github.com/bompus/oxide-worker-unload-repro.git
cd oxide-worker-unload-repro
npm install
node compare.cjs 20
node repro.cjs runs a single baseline trial. node repro.cjs --retain first loads the same Oxide package in the main thread. Clear any diagnostic/preload NODE_OPTIONS before comparing.
Describe your issue
A Node worker creates a Scanner and scans 100 in-memory HTML strings, then exits naturally. The parent stays alive for another 500 ms. Expected: the scanner produces flex, the worker exits successfully, and the parent exits 0. Actual: the process intermittently exits with 0xC0000005 rather than a JavaScript exception.
The fresh minimal project produced these results from 20 sequential pairs, reversing baseline/retention order on alternate pairs:
| Arm | Passed | Access violations |
|---|---|---|
| Oxide loaded only in worker | 18/20 | 2/20 |
| Same package also loaded in main thread | 20/20 | 0/20 |
Failing baseline trials were 7 and 19, both with process status 3221225477 (0xC0000005), no stdout, and no stderr. This is intermittent: one passing run does not exclude the bug, and these counts are not a general failure-rate claim.
Native evidence from the original build
A locally captured dump of the failing Expo update-resource subprocess yielded:
ExceptionCode: c0000005
ExceptionAddress: <Unloaded_tailwindcss-oxide.win32-x64-msv>+0x212ec6
Parameter[0]: 8 (execute access)
Memory state/protection: MEM_FREE / PAGE_NOACCESS
Failure bucket: SOFTWARE_NX_FAULT_INVALID_POINTER_EXECUTE_c0000005_tailwindcss-oxide.win32-x64-msv!Unloaded
The dump came from the original build, not the minimal reproduction. It establishes an attempt to execute unloaded Oxide code. The remaining stack was not reliable enough to identify a specific Rust function or thread owner. No dump is uploaded here.
Workaround and possible direction
Requiring UniWind's resolved Oxide dependency in the main thread before worker creation passed ten earlier small trials and three alternating full APK builds; one of those three full-build baseline trials crashed. The newly isolated comparison above independently reproduced the same baseline/workaround distinction.
Oxide's scanner uses Rayon's parallel iterators. Native thread lifetime versus library unloading is a plausible mechanism, not yet a symbolically proven identification of the faulting thread. Related discussion: https://github.com/rayon-rs/rayon/issues/1101 and https://github.com/rayon-rs/rayon/issues/1242.
A proposed Windows library-retention fix and regression test are in draft PR #20471. Comparing release binaries built from upstream f723e83 and the patch in another 20 alternating pairs reproduced two baseline access violations and zero patched failures. The regression fixture's explicit library-retention assertion failed 20/20 unmodified runs and passed 20/20 patched runs. The PR documents validation limits, including eight scanner symlink test failures also reproduced on untouched upstream. A process-lifetime pin intentionally keeps the native library mapped until Node exits; it does not implement native thread-pool shutdown.
- Dominant language
- TypeScript
- Stars
- 97.9k
- Forks
- 8.9k
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 24
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from tailwindlabs/tailwindcss
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
tailwindlabs/tailwindcss#20491 · 1 reaction ·
Maintainers usually reply within 1 day
-
Scanner `globs` walks gitignored directories (files pass respects .gitignore, globs pass does not)May be free again @akasakariko claimed this 19 days ago, and no pull request is open. Open
Difficulty 3/5 1-2 days Newbie friendliness 58/100
tailwindlabs/tailwindcss#20533 · 3 comments ·
Maintainers usually reply within 1 day
-
Source detection ignores `core.excludesFile`, so globally-ignored directories are scanned (reproduction for #19801)Possibly taken @Lukecele claimed this 24 days ago. Open
Difficulty 3/5 1-2 days Newbie friendliness 65/100
tailwindlabs/tailwindcss#20509 ·
Maintainers usually reply within 1 day
-
@tailwindcss/vite: cached Root.compiler pins the build's plugin context, keeping the finished bundle alive (multi-GB RSS in Astro SSG)Possibly taken @lazerg claimed this 30 days ago. Open
Difficulty 4/5 3-5 days Newbie friendliness 68/100
tailwindlabs/tailwindcss#20501 · 4 comments ·
Maintainers usually reply within 1 day
-
needs reproduction
Difficulty 4/5 3-5 days Newbie friendliness 45/100
tailwindlabs/tailwindcss#20464 · 9 comments ·
Maintainers usually reply within 1 day
All issues in tailwindlabs/tailwindcss
Similar issues
-
[BUG] rag: sentence content can cross the reported sentence boundariesPossibly taken @LJK-ikun claimed this today. Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day
-
bug needs-triage
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 1 day
-
README: the Resource URI Schemas example's file://documents/* pattern only matches that literal URIOpen
Difficulty 1/5 Under an hour Newbie friendliness 88/100
platformatic/mcp#361 ·
Maintainers usually reply within 1 day
-
frontend
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Push: sem service worker ou sem VAPID, o interruptor de Notificações fica ligado sem avisar nadaOpen
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
melgarafael/DeskcommCRM#3164 ·
Maintainers usually reply within 1 day