denoland/deno · error · TypeError

ERR_INVALID_ARG_VALUE

ERR_INVALID_ARG_VALUE

Error message

The property 'options.recursive' is no longer supported. Received ${inspect(value)}

What it means

Node removed the recursive option from fs.rmdir (deprecated since v14.14, hard error in v16+); Deno's polyfill follows suit and throws ERR_INVALID_ARG_VALUE('options.recursive', ..., 'is no longer supported') instead of silently doing a non-recursive rmdir. The check fires before any filesystem operation.

Source

Thrown at ext/node/polyfills/fs.ts:1876

function rmdir(
  path: string | Buffer | URL,
  options: rmdirOptions,
  callback: rmdirCallback,
): void;
function rmdir(
  path: string | Buffer | URL,
  options: rmdirOptions | rmdirCallback | undefined,
  callback?: rmdirCallback,
) {
  if (typeof options === "function") {
    callback = options;
    options = undefined;
  }

  if (options?.recursive !== undefined) {
    // The `recursive` option was deprecated and removed in Node. Throw with a
    // clear message rather than silently doing the wrong thing.
    throw new ERR_INVALID_ARG_VALUE(
      "options.recursive",
      options.recursive,
      "is no longer supported",
    );
  }

  validateFunction(callback, "cb");
  path = getValidatedPathToString(path);

  validateRmdirOptions(options);
  PromisePrototypeThen(
    op_node_rmdir(path),
    (_) => callback(),
    (err: Error) =>
      callback(
        denoErrorToNodeError(err, { syscall: "rmdir", path }),
      ),
  );

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Replace with fs.rm(dir, { recursive: true }, cb) — rm supports recursive removal
  2. Set recursive: undefined or omit the key entirely if you truly want a non-recursive rmdir
  3. Audit dependencies for rmdir recursive usage after upgrading Node/Deno

Example fix

// before
fs.rmdir(dir, { recursive: true }, cb); // ERR_INVALID_ARG_VALUE

// after
fs.rm(dir, { recursive: true }, cb);
Defensive patterns

Strategy: validation

Validate before calling

const removeDir = (dir: string, recursive: boolean, cb: (e?: Error | null) => void) =>
  recursive ? fs.rm(dir, { recursive: true }, cb) : fs.rmdir(dir, cb);

Type guard

const hasRecursive = (o: unknown): o is { recursive: boolean } =>
  typeof o === 'object' && o !== null && 'recursive' in o && (o as any).recursive !== undefined;

Prevention

When it happens

Trigger: fs.rmdir(dir, { recursive: true }, cb) — including falsy-but-present values like recursive: false? No: only when options.recursive !== undefined, so { recursive: undefined } passes but any defined value throws.

Common situations: Old tutorials and pre-Node-14 code using rmdir for recursive deletion; dependencies that have not been updated for modern Node semantics; CI upgrading from Node 12-era behavior.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/099f68a0b8cb5f67. Report an issue: GitHub.