denoland/deno · error · TypeError

ERR_INVALID_ARG_TYPE

ERR_INVALID_ARG_TYPE

Error message

The "options" argument must be of type object or integer. Received ${actual}

What it means

dns.lookup's second parameter is polymorphic: a function (treated as the callback), a number (an IP family, later validated against 0/4/6), or an object/undefined (lookup options). Any other type — string, boolean, bigint, symbol — reaches the final else-branch and throws ERR_INVALID_ARG_TYPE for 'options'.

Source

Thrown at ext/node/polyfills/dns.ts:219

  let port = undefined;

  // Parse arguments
  if (hostname) {
    validateString(hostname, "hostname");
  }

  if (isLookupCallback(options)) {
    callback = options;
    family = 0;
  } else if (isFamily(options)) {
    validateFunction(callback, "callback");

    validateOneOf(options, "family", validFamilies);
    family = options;
  } else if (!isLookupOptions(options)) {
    validateFunction(arguments.length === 2 ? options : callback, "callback");

    throw new ERR_INVALID_ARG_TYPE("options", ["integer", "object"], options);
  } else {
    validateFunction(callback, "callback");

    if (options?.hints != null) {
      validateNumber(options.hints, "options.hints");
      hints = options.hints >>> 0;
      validateHints(hints);
    }

    if (options?.family != null) {
      // Accept both numeric (0, 4, 6) and string ('IPv4', 'IPv6') family values
      // to match Node.js behavior
      switch (options.family) {
        case "IPv4":
          family = 4;
          break;
        case "IPv6":
          family = 6;

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Use the numeric shorthand dns.lookup(host, 4, cb) or the options object dns.lookup(host, { family: 4 }, cb)
  2. Coerce config-provided families: Number(family) guarded by Number.isInteger
  3. For 'IPv4'/'IPv6' strings, pass them inside the options object ({ family: 'IPv6' }), which the polyfill accepts

Example fix

// before
dns.lookup('example.com', 'IPv6', (err, addr) => {}); // string options -> throws

// after
dns.lookup('example.com', { family: 'IPv6' }, (err, addr) => {});
Defensive patterns

Strategy: validation

Validate before calling

// Normalize the polymorphic second arg before dns.lookup
function normalizeLookupArgs(hostname, options, callback) {
  if (typeof options === 'function') return [hostname, 0, options];
  if (typeof options === 'number') return [hostname, options, callback];
  if (options == null || typeof options === 'object') return [hostname, options ?? {}, callback];
  throw new TypeError(`bad lookup options: ${typeof options}`);
}

Type guard

const isLookupOptionsLike = (v) =>
  typeof v === 'function' || typeof v === 'number' || typeof v === 'object' || typeof v === 'undefined';

Prevention

When it happens

Trigger: dns.lookup('example.com', 'IPv4', cb) (family string instead of an options object); dns.lookup(host, true, cb); dns.lookup(host, 4n, cb); passing an array of families.

Common situations: Porting getaddrinfo-style code where family was a string; config values typed as '4'/'6' strings; passing { family: 4 } correctly but passing '4' bare as the shorthand.

Related errors


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