Repository navigation
Stop throwing for unsupported options in Worker's execArgv and env.NODE_OPTIONS. #41103
Description
Activity
@nodejs/workers
- addedworkerIssues and PRs related to the worker_threads module and Worker API.Issues and PRs related to the worker_threads module and Worker API.
on Dec 7, 2021 - changed the title
[-]Stop throwing for unsupported options in `Worker`'s `execArgv`.[/-][+]Stop throwing for unsupported options in `Worker`'s `execArgv` and `env.NODE_OPTIONS`.[/+]on Dec 11, 2021 The same happens with
env.When running
NODE_OPTIONS=--openssl-legacy-provider node test.jswith Node.js 17.2.0, this works:const { Worker, isMainThread } = require("worker_threads"); if (isMainThread) { new Worker(__filename); } else { console.log("From worker!", process.env.NODE_OPTIONS); }
but this throws
const { Worker, isMainThread } = require("worker_threads"); if (isMainThread) { new Worker(__filename, { env: process.env }); } else { console.log("From worker!", process.env.NODE_OPTIONS); }
You can see that the
gcfunction is present. This means that the disallowed flags are not ignored (and not even "ignored but still used to populate theprocess.execArgvarray): they are used and affect the runtime behavior.This may be not right, as:
const { isMainThread, Worker } = require("worker_threads"); if (isMainThread) { new Worker(__filename, { execArgv: [] }); } else { console.log("Hello from the worker!", process.execArgv, globalThis.gc); }
run
node --expose_gc test.jswill log:Hello from the worker! [] [Function: gc]Seems that this behavior is not controlled by work's
execArgv.If
execArgvis not specified, all parent's args indeed are used:Lines 551 to 553 in 4cb2a47
} else { exec_argv_out = env->exec_argv(); } Lines 308 to 315 in 4cb2a47
env_.reset(CreateEnvironment( data.isolate_data_.get(), context, std::move(argv_), std::move(exec_argv_), static_cast<EnvironmentFlags::Flags>(environment_flags_), thread_id_, std::move(inspector_parent_handle_))); But since these Per-Process options and V8 flags are from parents, I guess it is ok?
- added a commit that references this issue
on Aug 4, 2022 this have for sure been bugging me too, some flags gets added or removed in different versions.
one needs to be able to figure out what flags are supported or not before you can pass this execArgv commandsJust ran into this using
avaavajs/ava#3207What's the word on this? Just hit this on taskforcesh/bullmq#2075 which is a pain because without a change to that package, worker_threads can't be used.
+1 for Ignore the unsupported options
Opened #53596 for the simpler case of NODE_OPTIONS, when the worker spawning code does not intend to modify NODE_OPTIONS and only copies the one from the parent because they want to update other environment variables.
- added 2 commits that reference this issue
on Jul 12, 2024 I came across this error while building angular 18 app. I solved it by disabling SSR "prerender": false, "ssr": false inside project.json file
I ran into this when building an old project that uses mocha-parallel-test and node's --openssl-legacy-provider option.
mocha-parallel-tests spawns workers and specifies execArgv to remove some 'debug' flags from the process execArgv. But it doesn't remove openssl-legacy-provider so node throwsError [ERR_WORKER_INVALID_EXEC_ARGV]: Initiated Worker with invalid execArgv flags: --openssl-legacy-providerhttps://github.com/mocha-parallel/mocha-parallel-tests/blob/master/src/main/thread/worker.ts#L35-L36
Either node should ignore these options by default, as it appears to when using the default execArgv, or node should provide a function to remove unsupported options, or return
process.execArgvwithout per-process arguments.github-actions commented
on Jun 25, 2026 on Jun 25, 2026 – with GitHub ActionsContributorMore actionsThis issue has been marked as stale due to 210 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.Reacted by Michael Kriese- addedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Jun 25, 2026 bump
- removedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Jun 26, 2026 github-actions commented
on Sep 25, 2026 on Sep 25, 2026 – with GitHub ActionsContributorMore actionsThis issue has been marked as stale due to 90 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.Reacted by Michael Kriese- addedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Sep 25, 2026 Fairly sure this is still an issue.
Reacted by Alan Agius- removedstaleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
on Sep 26, 2026
Version
v17.2.0
Platform
No response
Subsystem
worker_threads
What steps will reproduce the bug?
Consider this
test.jsfile:Run these two commands:
They will log
Now, uncomment the
execArgv: process.execArgvline and run the two commands again. The first command will still loghowever, the second one throws:
This mans that the default behavior of the Worker
execArgvoption is not to inheritexecArgvfrom the parent thread (contrary to what the documentation says).Why would you want to explicitly pass
execArgv: process.execArgvanyway?A few days ago I was trying to implement a require hook that internally uses a
Worker, and in order to avoid registering it recursively in an infinite worker-spawn loop I tried to filter out the--requireflag:this seemed to work, until it crashed in a test that was using the
--expose_gcoption.Today, I found the exact same problem in
jest-worker(a Jest subpackage that is often also used outside of Jest): jestjs/jest#12103 was opened becausejest-workerdidn't work when running Node.js with--max_old_space_size.Since Node.js doesn't provide the list of flags supported by workers progrmmatically (and I didn't find it in the docs either 😅) there is no way to filter the
execArgvused by a worker.What is the current behavior?
I initially expected the real default behavior to be something like
execArgv: process.execArgv.filter(isSupportedByWorker), but it looks like it's not either. Consider for example the--expose_gc(which is disallowed in workers) option with this example:If you run
node --expose_gc test.js, it will logYou can see that the
gcfunction is present. This means that the disallowed flags are not ignored (and not even "ignored but still used to populate theprocess.execArgvarray): they are used and affect the runtime behavior.How often does it reproduce? Is there a required condition?
Only for the options marked as "unsupported" in workers.
What is the expected behavior?
I see four possible solutions:
execArgv).execArgvof the parent thread.execArgv: process.execArgvbecomes the default behavior), and provide aWorker.filterExecArgvutility that removes disallowed options, and that I would have used likeIf the current behavior is expected, then the docs should be updated to mention that the default value cannot be replicated by explicitly passing an
execArgvoption.What do you see instead?
No response
Additional information
No response