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
- Pass a plain string path
- Default the value: process.chdir(dir ?? process.cwd())
- Validate with typeof dir === 'string' and non-empty at the config boundary
- 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
- Resolve config paths early with a required-string helper
- Remember chdir accepts only strings - no URL or path objects
- Prefer absolute paths so cwd changes cannot break later relative lookups
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
- No callback function supplied
- invalid ${name}, must not be infinity or NaN
- resolve hook must return { shortCircuit: true } or call next
- load hook must return { shortCircuit: true } or call nextLoa
- A file exists at the destination: ${destStr}
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/603f3ee1d02c50e6.
Report an issue: GitHub.