denoland/deno · error · TypeError

ERR_INVALID_ARG_TYPE

ERR_INVALID_ARG_TYPE

Error message

The "options" argument must be of type object. Received ${actual}

What it means

ChildProcess#spawn(options) is the internal spawn entry point in Deno's child_process polyfill, called after a ChildProcess instance is constructed. It requires `options` to be a non-null object; passing null, undefined, a string, or a primitive throws ERR_INVALID_ARG_TYPE before any field is read. User-facing spawn()/fork() build this object for you, so hitting this means the internal method was called directly or an option object was dropped along the way.

Source

Thrown at ext/node/polyfills/internal/child_process.ts:332

  constructor() {
    super();

    // 'child_process' channel fires once per ChildProcess construction, before
    // spawn(). cluster.fork() / cp.fork() / cp.spawn() all flow through here,
    // so a single publish site covers every entry point.
    if (childProcessChannel.hasSubscribers) {
      childProcessChannel.publish({ process: this });
    }
  }

  /**
   * Internal spawn method used by Node.js internals.
   * This is called after creating a ChildProcess instance.
   */
  spawn(options) {
    // Validate options
    if (options == null || typeof options !== "object") {
      throw new ERR_INVALID_ARG_TYPE("options", "object", options);
    }

    // Validate envPairs before file (Node.js validation order)
    const { envPairs } = options;
    if (envPairs !== undefined && !ArrayIsArray(envPairs)) {
      throw new ERR_INVALID_ARG_TYPE("options.envPairs", "Array", envPairs);
    }

    // Validate args
    const { args } = options;
    if (args !== undefined && !ArrayIsArray(args)) {
      throw new ERR_INVALID_ARG_TYPE("options.args", "Array", args);
    }

    // Validate file
    const { file } = options;
    if (file == null || typeof file !== "string") {
      throw new ERR_INVALID_ARG_TYPE("options.file", "string", file);

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Prefer the public spawn(command, args, options) / fork() APIs which construct and validate the options object internally
  2. If using the internal method, always pass a plain object, defaulting to {}
  3. Check `options == null || typeof options !== 'object'` and fail early with your own message

Example fix

// before
const cp = new ChildProcess();
cp.spawn(maybeOpts); // maybeOpts can be undefined

// after
const cp = new ChildProcess();
cp.spawn(maybeOpts ?? {});
Defensive patterns

Strategy: type-guard

Validate before calling

if (options == null || typeof options !== 'object' || Array.isArray(options)) {
  throw new TypeError('spawn options must be a plain object');
}

Type guard

const isSpawnOptions = (o) => o != null && typeof o === 'object' && !Array.isArray(o);

Try / catch

try { child.spawn(options); } catch (err) {
  if (err?.code === 'ERR_INVALID_ARG_TYPE' && err.message.includes('"options"')) {
    child.spawn({}); // retry with safe defaults
  }
}

Prevention

When it happens

Trigger: Calling child.spawn(null), child.spawn('node'), or a custom spawn wrapper that forwards `undefined` options (e.g. spawn(opts || undefined) where the falsy branch wins).

Common situations: Subclassing ChildProcess or re-implementing normalizeSpawnArguments in app code; optional-chaining bugs where options ?? undefined reaches the internal call; porting code from older Node internals with a different spawn signature.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


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