Skip to content

fix(worker): route worker_threads errors like the web surface, and fire once listeners once - #491

Open
adrian-niculescu wants to merge 2 commits into
NativeScript:mainfrom
adrian-niculescu:fix/worker-threads-error-routing
Open

adrian-niculescu wants to merge 2 commits into
NativeScript:mainfrom
adrian-niculescu:fix/worker-threads-error-routing

Conversation

@adrian-niculescu

@adrian-niculescu adrian-niculescu commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

A parentPort.on("message") listener that throws never reaches the worker's onerror or the parent's worker.on("error"). The relay dispatched without rethrowing, so the throw went to the uncaught-error reporter and stopped there. It now dispatches the way worker-global message delivery does.

An error that a worker.on("error") listener handled was also reported to the parent's global scope as unhandled, because the Worker's onerror returned nothing. It now returns whether a listener ran, which cancels the event, and the emitter reports that the way Node's emit does.

A once listener could fire twice: when an earlier listener emitted the same event again, the nested emit fired and removed it, and the outer emit then called it a second time from its snapshot. A once registration now records that it fired, as Node's once wrapper does, so a once listener an earlier listener removed still fires, as in Node.

The same fix for Android is NativeScript/android#2065. All three new specs fail on main and pass here, and the full TestRunner suite passes.

Summary by CodeRabbit

  • Bug Fixes
    • Worker errors handled by their registered error listeners are no longer also reported to the parent scope’s global error listener.
    • One-time event listeners now run only once, even when an event is emitted again recursively while the listener is running.
    • Errors thrown by message handlers are delivered to the parent worker’s error listener exactly once.

…errors like the web surface

A parentPort listener that threw was dispatched without rethrowing, so the error went to the uncaught-error reporter and never reached the worker's onerror or its parent. The relay now dispatches the way worker-global message delivery does.

The worker_threads Worker's onerror handler returned nothing, so an error its 'error' listeners took was also reported to the parent's global scope as unhandled. It returns whether a listener ran, which cancels the event.
@coderabbitai

coderabbitai Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 28ff14d2-d3cf-4519-99ec-2164703f224c
📥 Commits

Reviewing files that changed from the base of the PR and between 4ae32eb and e823dff.

📒 Files selected for processing (3)
  • NativeScript/runtime/js/node-worker-threads.js
  • TestRunner/app/tests/MessagingTests.js
  • TestRunner/app/tests/messaging/parentPortThrowingWorker.js

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Worker event emission now reports whether listeners were registered and prevents a once-listener from firing again during nested emission. Worker-scope error forwarding uses rethrowing dispatch. New regression tests cover these event and error cases.

Changes

Worker event handling

Layer / File(s) Summary
Emission results and once-listeners
NativeScript/runtime/js/node-worker-threads.js, TestRunner/app/tests/MessagingTests.js
WorkerEmitter.emit returns false when no listeners are registered and true after dispatch. Once-listeners are marked fired before invocation. A regression test checks that recursive emission does not invoke a once-listener again.
Worker error forwarding
NativeScript/runtime/js/node-worker-threads.js, TestRunner/app/tests/MessagingTests.js, TestRunner/app/tests/messaging/parentPortThrowingWorker.js
The worker error handler returns the result of emitting "error", and the worker-scope relay uses dispatchEventRethrowing. Regression tests check handled worker errors and errors thrown by parentPort message listeners.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: edusperoni

Merge Risk: ⚪ Minimal · up to e823d

The reviewed worker error and once-listener paths show no actionable merge-blocking issue. Merge after normal checks.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies both main changes: worker error routing and reentrant once-listener behavior.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 3…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit taps a message through,
A once-listener runs once, not two.
An error finds its listener’s ear,
The worker sends the signal clear.
Then hops away, with tests in view.

Comment @coderabbitai help to get the list of available commands.

… reentrant emit

An earlier listener that emitted the same event again let the nested emit fire and remove a later once listener, and the outer emit then called it a second time from its snapshot. A once registration now records that it fired, as Node's once wrapper does.
@adrian-niculescu adrian-niculescu changed the title fix(worker): route parentPort listener throws and handled Node-style errors like the web surface fix(worker): route worker_threads errors like the web surface, and fire once listeners once Oct 6, 2026
@adrian-niculescu
adrian-niculescu marked this pull request as ready for review October 6, 2026 19:22

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant