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.

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: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

  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 a961cdec3b)