denoland/deno · error · NodeTypeError

ERR_INVALID_ARG_TYPE

ERR_INVALID_ARG_TYPE

Error message

The "path" argument must be of type string or an instance of Buffer. Received ${actual}

What it means

The internal join helper that appends a directory-entry name to a base path accepts exactly two combinations: both arguments strings, or both Uint8Array/Buffer. A mixed pair (string + Buffer) or any other type matches neither branch and the helper throws ERR_INVALID_ARG_TYPE for the path argument. It backs readdir's dirent assembly, so type inconsistency between a base path and entry names is what surfaces it.

Source

Thrown at ext/node/polyfills/internal/fs/utils.mjs:281

      lazyPath().default.join(path, lazyPath().default.sep),
    );
    // Ignore lint. `concat` is a 'node:buffer' static method on `Buffer`
    // deno-lint-ignore deno-internal/prefer-primordials
    return Buffer.concat([pathBuffer, name]);
  }

  if (typeof path === "string" && typeof name === "string") {
    // deno-lint-ignore deno-internal/prefer-primordials -- `join` is a `node:path` function
    return lazyPath().default.join(path, name);
  }

  if (isUint8Array(path) && isUint8Array(name)) {
    // Ignore lint. `concat` is a 'node:buffer' static method on `Buffer`
    // deno-lint-ignore deno-internal/prefer-primordials
    return Buffer.concat([path, bufferSep, name]);
  }

  throw new ERR_INVALID_ARG_TYPE(
    "path",
    ["string", "Buffer"],
    path,
  );
}

export function getDirents(path, { 0: names, 1: types }, callback) {
  let i;
  if (typeof callback === "function") {
    const len = names.length;
    let toFinish = 0;
    callback = once(callback);
    for (i = 0; i < len; i++) {
      const type = types[i];
      if (type === UV_DIRENT_UNKNOWN) {
        const name = names[i];
        const idx = i;
        toFinish++;

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Make both operands the same type: path.toString('utf8') + name, or Buffer.concat([path, Buffer.from(name)]).
  2. Consume fs.Dirent directly (readdir with withFileTypes) and build paths with a single type discipline.
  3. Avoid Buffer paths unless NUL-byte-safe names are a hard requirement.

Example fix

// before (mixed types)
const full = join(bufPath, stringName); // Buffer + string -> throws

// after
const full = path.join(bufPath.toString('utf8'), stringName);
// or stay binary
const full = Buffer.concat([bufPath, Buffer.from('/'), Buffer.from(stringName)]);
Defensive patterns

Strategy: type-guard

Validate before calling

const sameType = (a, b) =>
  (typeof a === 'string' && typeof b === 'string') ||
  (a instanceof Uint8Array && b instanceof Uint8Array);
if (!sameType(base, name)) {
  throw new TypeError('path and name must both be strings or both Buffers');
}

Type guard

function isHomogeneousPair(path, name) {
  if (typeof path === 'string' && typeof name === 'string') return true;
  if (path instanceof Uint8Array && name instanceof Uint8Array) return true;
  return false;
}

Prevention

When it happens

Trigger: Feeding readdir results back with mismatched types: a Buffer base path (encoding: 'buffer') combined with string names from another call, or the reverse; direct misuse of the internal join with heterogeneous arguments.

Common situations: Binary-safe path pipelines that convert only one side to Buffer; refactors that change one variable's type mid-pipeline; appending fs.Dirent names to a Buffer parent path.

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@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/d58a6adfdf2d7e7c. Report an issue: GitHub.