Skip to content

fix(scripting/node): remove premature Stop() call before FreeEnvironment()#3854

Open
gtolontop wants to merge 1 commit intocitizenfx:masterfrom
gtolontop:fix/node-worker-thread-crash
Open

fix(scripting/node): remove premature Stop() call before FreeEnvironment()#3854
gtolontop wants to merge 1 commit intocitizenfx:masterfrom
gtolontop:fix/node-worker-thread-crash

Conversation

@gtolontop
Copy link

Goal of this PR

Fix a server crash (FATAL ERROR: v8::Isolate::Dispose() Disposing the isolate that is entered by a thread) when a Node 22 worker thread is terminated or when a script using workers is stopped.

How is this PR achieving the goal

The Destroy() shutdown sequence called node::Stop(m_nodeEnvironment) right before node::FreeEnvironment(m_nodeEnvironment). This is problematic because:

  1. node::Stop() calls isolate_->TerminateExecution(), which sets a V8 termination flag on the isolate
  2. node::FreeEnvironment() then calls stop_sub_worker_contexts(), which tries to Exit() and JoinThread() each worker
  3. Workers are still entered on the isolate when it gets terminated, causing the V8 fatal error

The fix removes the node::Stop() call. node::FreeEnvironment() already handles the full shutdown sequence: it sets stopping = true, sets can_call_into_js = false, stops and joins sub-workers, runs cleanup hooks, runs AtExit hooks, and deletes the environment. This matches Node.js's own CommonEnvironmentSetup destructor which does not call Stop() before FreeEnvironment().

This PR applies to the following area(s)

FiveM and RedM Node.js scripting runtime (citizen-scripting-node)

Successfully tested on

  • Worker thread creation and termination via worker.terminate() no longer crashes
  • Script stop/restart with active workers no longer crashes
  • Normal script shutdown without workers remains unaffected

Checklist

  • Code compiles and has been tested successfully.
  • Code explains itself well and/or is documented.
  • My commit message explains what the changes do and what they are for.
  • No extra compilation warnings are added by these changes.

Fixes issues

Fixes #3846

…ent() node::Stop() calls isolate_->TerminateExecution() which terminates the main isolate while worker threads are still entered on it. FreeEnvironment() already handles the full shutdown sequence including stop_sub_worker_contexts(), RunCleanup(), and RunAtExit(), making the Stop() call both redundant and harmful.
@github-actions github-actions bot added the invalid Requires changes before it's considered valid and can be (re)triaged label Mar 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

invalid Requires changes before it's considered valid and can be (re)triaged

1 participant