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
- Pass an object or omit the argument entirely: interceptors.deduplicate() uses defaults.
- Normalize dynamic config: const opts = config ?? undefined before composing.
- 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
- Omit the argument to use defaults.
- Normalize config with ?? undefined before forwarding.
- Guard typeof at the boundary.
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
- expected ${name} to be an array or undefined, got ${typeof o
- expected ${name}[${i}] to be a string or RegExp, got ${typeo
- expected type of opts to be an Object, got ${opts === null ?
- expected opts.cacheByDefault to be number or undefined, got
- expected opts.type to be shared, private, or undefined, got
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/04d3ed8b280ac428.
Report an issue: GitHub.