denoland/deno · error · ERR_WORKER_INVALID_EXEC_ARGV

ERR_WORKER_INVALID_EXEC_ARGV

ERR_WORKER_INVALID_EXEC_ARGV

Error message

Initiated Worker with invalid execArgv flags: ${invalidFlags}

What it means

ERR_WORKER_INVALID_EXEC_ARGV is thrown by the Worker constructor when options.execArgv contains flags that are not recognized Node environment flags, or are valid process-wide flags that are forbidden inside workers because they mutate per-process state. Deno's polyfill checks each leading-'-' token against process.allowedNodeEnvironmentFlags plus a disallowed set (--title, --redirect-warnings, --report-*, tracing/diagnostic flags); V8 profiling flags (--cpu-prof*, --heap-prof*) are accepted and silently ignored.

Source

Thrown at ext/node/polyfills/worker_threads.ts:330

            continue;
          }
          const eqIdx = StringPrototypeIndexOf(flag, "=");
          const flagName = eqIdx === -1
            ? flag
            : StringPrototypeSlice(flag, 0, eqIdx);
          if (workerSilentlyIgnoredFlags.has(flagName)) {
            continue;
          }
          if (!lazyProcess().default.allowedNodeEnvironmentFlags.has(flag)) {
            invalidFlags[invalidFlags.length] = flag;
            continue;
          }
          if (workerDisallowedFlags.has(flagName)) {
            invalidFlags[invalidFlags.length] = flag;
          }
        }
        if (invalidFlags.length > 0) {
          throw new ERR_WORKER_INVALID_EXEC_ARGV(invalidFlags);
        }
      }
    }

    if (options?.env) {
      const nodeOptions = options.env.NODE_OPTIONS;
      if (typeof nodeOptions === "string" && nodeOptions.length > 0) {
        // Parse NODE_OPTIONS and validate each flag
        const parts = StringPrototypeSplit(
          StringPrototypeTrim(nodeOptions),
          new SafeRegExp("\\s+"),
        );
        let hasInvalid = false;
        for (let i = 0; i < parts.length; i++) {
          const part = parts[i];
          if (StringPrototypeStartsWith(part, "-")) {
            const eqIdx = StringPrototypeIndexOf(part, "=");
            const partName = eqIdx === -1

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Filter execArgv to flags you know are allowed before constructing the Worker (see validationCode).
  2. Remove worker-forbidden flags from the list: --title, --redirect-warnings, --trace-event-file-pattern, --trace-event-categories, --trace-events-enabled, --diagnostic-dir, --report-signal, --report-filename, --report-dir, --report-directory, --report-compact, --report-on-signal, --report-on-fatalerror, --report-uncaught-exception.
  3. Fix or unset a bad NODE_OPTIONS in the environment (`env | grep NODE_OPTIONS`) when the error comes from options.env rather than execArgv.

Example fix

// before
new Worker(filename, { execArgv: process.execArgv }); // may carry --title etc.

// after
const workerForbidden = new Set(['--title', '--redirect-warnings', '--diagnostic-dir',
  '--report-signal', '--report-filename', '--report-dir', '--report-directory',
  '--report-compact', '--report-on-signal', '--report-on-fatalerror',
  '--report-uncaught-exception', '--trace-event-file-pattern',
  '--trace-event-categories', '--trace-events-enabled']);
const execArgv = process.execArgv.filter((f) => {
  const name = f.split('=')[0];
  return !workerForbidden.has(name) && process.allowedNodeEnvironmentFlags.has(name);
});
new Worker(filename, { execArgv });
Defensive patterns

Strategy: validation

Validate before calling

const WORKER_FORBIDDEN_FLAGS = new Set([
  '--title', '--redirect-warnings', '--trace-event-file-pattern',
  '--trace-event-categories', '--trace-events-enabled', '--diagnostic-dir',
  '--report-signal', '--report-filename', '--report-dir', '--report-directory',
  '--report-compact', '--report-on-signal', '--report-on-fatalerror',
  '--report-uncaught-exception',
]);
function sanitizeExecArgv(flags: string[]): string[] {
  return flags.filter((flag) => {
    if (!flag.startsWith('-')) return true; // flag arguments pass through
    const name = flag.split('=')[0];
    if (WORKER_FORBIDDEN_FLAGS.has(name)) return false;
    return process.allowedNodeEnvironmentFlags.has(name);
  });
}
new Worker(filename, { execArgv: sanitizeExecArgv(process.execArgv) });

Type guard

function isWorkerSafeFlag(flag: string): boolean {
  if (!flag.startsWith('-')) return true;
  const name = flag.split('=')[0];
  if (WORKER_FORBIDDEN_FLAGS.has(name)) return false;
  return process.allowedNodeEnvironmentFlags.has(flag);
}

Try / catch

try {
  worker = new Worker(filename, { execArgv });
} catch (err) {
  if ((err as { code?: string }).code === 'ERR_WORKER_INVALID_EXEC_ARGV') {
    worker = new Worker(filename, { execArgv: sanitizeExecArgv(execArgv) });
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: `new Worker(file, { execArgv: ['--title=main'] })`, `execArgv: ['--max-old-space-size=4096', '--unsupported-flag']`, or flags forwarded from the parent that include worker-forbidden entries; the same validation runs against flags found in options.env.NODE_OPTIONS.

Common situations: Forwarding `process.execArgv` into every worker unconditionally; CI or prod harnesses that inject report/tracing flags globally; scripts assuming Deno rejects nothing in execArgv; misconfigured NODE_OPTIONS in the environment.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/e0e784fcfe7e0742. Report an issue: GitHub.