denoland/deno · error · NodeTypeError

ERR_INVALID_ARG_TYPE

ERR_INVALID_ARG_TYPE

Error message

The "directory" argument must be of type string. Received ${directory}

What it means

process.chdir(directory) validates its argument up front: anything that is not a string (null, undefined, number, object, URL) throws ERR_INVALID_ARG_TYPE('directory', 'string', directory). The check runs before any syscall, so the current working directory is unchanged when it fires.

Source

Thrown at ext/node/polyfills/_process/process.ts:60

  if (build.arch == "x86_64") {
    return "x64";
  } else if (build.arch == "aarch64") {
    return "arm64";
  } else if (build.arch == "riscv64gc") {
    return "riscv64";
  } else if (build.arch == "loongarch64") {
    return "loong64";
  } else if (build.arch == "powerpc64le") {
    return "ppc64";
  } else {
    throw new Error("unreachable");
  }
}

/** https://nodejs.org/api/process.html#process_process_chdir_directory */
function chdir(directory: string): void {
  if (typeof directory !== "string") {
    throw new ERR_INVALID_ARG_TYPE("directory", "string", directory);
  }
  // Node's chdir error carries `path` (the cwd before chdir), `dest` (the
  // target), and `syscall: 'chdir'`. Snapshot the cwd before attempting the
  // change so the error's `path` matches Node's behaviour. If the current
  // cwd has been deleted (common in tmpdir cleanup during process exit),
  // `fs.cwd()` itself throws -- fall back to an empty string so the wrapper
  // still has a sensible `path`, and don't surface the cwd lookup error.
  let fromPath = "";
  try {
    fromPath = fs.cwd();
  } catch {
    // Ignore -- chdir() below will surface a chdir-shaped error.
  }
  try {
    fs.chdir(directory);
  } catch (err) {
    throw denoErrorToNodeError(err as Error, {
      syscall: "chdir",

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Pass a plain string path
  2. Default the value: process.chdir(dir ?? process.cwd())
  3. Validate with typeof dir === 'string' and non-empty at the config boundary
  4. Convert deliberately with String(dir) after an undefined check

Example fix

// before
process.chdir(config.workdir); // workdir is undefined

// after
if (typeof config.workdir !== 'string' || config.workdir === '') {
  throw new Error('config.workdir must be a directory path string');
}
process.chdir(config.workdir);
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof directory !== 'string' || directory.length === 0) {
  throw new TypeError('directory must be a non-empty string');
}
process.chdir(directory);

Type guard

const isDirectoryString = (v) => typeof v === 'string' && v.length > 0;

Try / catch

try {
  process.chdir(dir);
} catch (e) {
  if (e.code === 'ERR_INVALID_ARG_TYPE') {
    // argument was not a string: fix the caller's value
  } else if (e.code === 'ENOENT' || e.code === 'ENOTDIR') {
    // directory missing or not a directory
  } else throw e;
}

Prevention

When it happens

Trigger: process.chdir(null), process.chdir(123), process.chdir(new URL('file:///x')) (a URL object, not a string), or process.chdir(config.workdir) where config.workdir is undefined.

Common situations: Optional config values that are undefined by default; passing a URL or path object instead of a string; numbers leaking from parsed CLI input; a refactor that renames the variable leaving it undefined.

Related errors


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