nodejs/node · error · TypeError

expected type of opts to be an Object, got ${opts === null ?

Error message

expected type of opts to be an Object, got ${opts === null ? 'null' : typeof opts}

What it means

Thrown by the deduplicate() interceptor factory when the opts argument is not an object. The factory signature is (opts = {}), so opts must be an object or undefined (to use defaults); null, strings, numbers, arrays, and booleans are rejected. null is reported as 'null' rather than 'object'.

Source

Thrown at deps/undici/src/lib/interceptor/deduplicate.js:23

const DeduplicationHandler = require('../handler/deduplication-handler')
const { normalizeHeaders, makeCacheKey, makeDeduplicationKey } = require('../util/cache.js')

const pendingRequestsChannel = diagnosticsChannel.channel('undici:request:pending-requests')

/**
 * @param {import('../../types/interceptors.d.ts').default.DeduplicateInterceptorOpts} [opts]
 * @returns {import('../../types/dispatcher.d.ts').default.DispatcherComposeInterceptor}
 */
module.exports = (opts = {}) => {
  const {
    methods = ['GET'],
    skipHeaderNames = [],
    excludeHeaderNames = [],
    maxBufferSize = 5 * 1024 * 1024
  } = opts

  if (typeof opts !== 'object' || opts === null) {
    throw new TypeError(`expected type of opts to be an Object, got ${opts === null ? 'null' : typeof opts}`)
  }

  if (!Array.isArray(methods)) {
    throw new TypeError(`expected opts.methods to be an array, got ${typeof methods}`)
  }

  for (const method of methods) {
    if (!util.safeHTTPMethods.includes(method)) {
      throw new TypeError(`expected opts.methods to only contain safe HTTP methods, got ${method}`)
    }
  }

  if (!Array.isArray(skipHeaderNames)) {
    throw new TypeError(`expected opts.skipHeaderNames to be an array, got ${typeof skipHeaderNames}`)
  }

  if (!Array.isArray(excludeHeaderNames)) {
    throw new TypeError(`expected opts.excludeHeaderNames to be an array, got ${typeof excludeHeaderNames}`)

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Pass an object or omit the argument entirely: interceptors.deduplicate() uses defaults.
  2. Normalize dynamic config: const opts = config ?? undefined before composing.
  3. Guard with typeof opts === 'object' && opts !== null before forwarding.

Example fix

// before
client.compose(interceptors.deduplicate(maybeConfig)) // maybeConfig can be null

// after
client.compose(interceptors.deduplicate(maybeConfig ?? undefined))
// or simply
client.compose(interceptors.deduplicate())
Defensive patterns

Strategy: type-guard

Validate before calling

const dedupOpts = (typeof cfg === 'object' && cfg !== null) ? cfg : undefined
client.compose(interceptors.deduplicate(dedupOpts))

Type guard

function isDedupOpts(v) { return v == null || (typeof v === 'object' && !Array.isArray(v)) }

Try / catch

try { client.compose(interceptors.deduplicate(opts)) } catch (e) { if (e instanceof TypeError && /opts to be an Object/.test(e.message)) { client.compose(interceptors.deduplicate()) } else throw e }

Prevention

When it happens

Trigger: Calling interceptors.deduplicate(null), interceptors.deduplicate(false), interceptors.deduplicate('GET'), or forwarding a primitive as the opts argument.

Common situations: Conditionally passing config and accidentally forwarding null/undefined-as-null; spreading a config that resolved to a falsy primitive; misreading the API as accepting a method string.

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/04d3ed8b280ac428. Report an issue: GitHub.