denoland/deno · error · TypeError

ERR_INVALID_ARG_TYPE

ERR_INVALID_ARG_TYPE

Error message

The "fd" argument must be of type number or an instance of FileHandle. Received ${fd}

What it means

respondWithFD() accepts an fd that is either a raw numeric file descriptor or a FileHandle (from fs/promises open). Anything else — most commonly a file path string — throws ERR_INVALID_ARG_TYPE listing the accepted types.

Source

Thrown at ext/node/polyfills/http2.ts:3312

    }

    if (
      options.statCheck !== undefined &&
      typeof options.statCheck !== "function"
    ) {
      throw new ERR_INVALID_ARG_VALUE("options.statCheck", options.statCheck);
    }

    let streamOptions = 0;
    if (options.waitForTrailers) {
      streamOptions |= STREAM_OPTION_GET_TRAILERS;
      this[kState].flags |= STREAM_FLAGS_HAS_TRAILERS;
    }

    if (ObjectPrototypeIsPrototypeOf(FsFileHandle.prototype, fd)) {
      fd = fd.fd;
    } else if (typeof fd !== "number") {
      throw new ERR_INVALID_ARG_TYPE("fd", ["number", "FileHandle"], fd);
    }

    debugStreamObj(this, "initiating response from fd");
    this[kUpdateTimer]();
    this.ownsFd = false;

    const {
      headers,
      statusCode,
    } = prepareResponseHeadersObject(headersParam, options);

    setOtelServerStatus(this, statusCode);

    // Payload/DATA frames are not permitted in these cases
    if (
      statusCode === HTTP_STATUS_NO_CONTENT ||
      statusCode === HTTP_STATUS_RESET_CONTENT ||
      statusCode === HTTP_STATUS_NOT_MODIFIED ||

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Use respondWithFile(path, ...) when you only have a path
  2. Open the file first: const handle = await fs.promises.open(path, 'r'); then pass handle or handle.fd
  3. Validate before the call: typeof fd === 'number' || (fd && typeof fd.fd === 'number')
  4. Close the handle yourself afterwards — respondWithFD sets ownsFd = false and will not close it

Example fix

// before
stream.respondWithFD("/srv/big.bin", headers); // path string, not fd

// after
const handle = await fs.promises.open("/srv/big.bin", "r");
stream.respondWithFD(handle, headers);
stream.on("close", () => handle.close());
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof fd !== "number" && !(fd && typeof fd.fd === "number")) {
  // you probably have a path: use respondWithFile instead
  stream.respondWithFile(path, headers);
  return;
}

Type guard

function isFdLike(fd) {
  return typeof fd === "number" || (typeof fd === "object" && fd !== null && typeof fd.fd === "number");
}

Try / catch

try {
  stream.respondWithFD(fd, headers);
} catch (err) {
  if (err.code === "ERR_INVALID_ARG_TYPE") { /* fall back to respondWithFile(path) */ }
  throw err;
}

Prevention

When it happens

Trigger: Passing a path string instead of an opened descriptor (confusing respondWithFD with respondWithFile); passing a closed or fake object without an fd property; passing a Deno FsFile where FileHandle.prototype check fails.

Common situations: Migrating code between respondWithFile and respondWithFD; using callback-style fs.open and passing the path 'by habit'; holding a FileHandle from a different fs surface whose prototype does not match.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/080bd0b9f951e6d1. Report an issue: GitHub.