nodejs/node · error · TypeError
expected opts.excludeHeaderNames to be an array, got ${typeo
Error message
expected opts.excludeHeaderNames to be an array, got ${typeof excludeHeaderNames} What it means
Thrown by the deduplicate interceptor when `excludeHeaderNames` is destructured from `opts` (default `[]`) but is not an Array. Unlike `skipHeaderNames` (which skips deduplication entirely when present), `excludeHeaderNames` excludes the named headers from the deduplication *key* so that requests differing only in those headers are still coalesced. The factory lowercases the entries into a Set at construction time.
Source
Thrown at deps/undici/src/lib/interceptor/deduplicate.js:41
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}`)
}
if (!Number.isFinite(maxBufferSize) || maxBufferSize <= 0) {
throw new TypeError(`expected opts.maxBufferSize to be a positive finite number, got ${maxBufferSize}`)
}
// Convert to lowercase Set for case-insensitive header matching
const skipHeaderNamesSet = new Set(skipHeaderNames.map(name => name.toLowerCase()))
// Convert to lowercase Set for case-insensitive header exclusion from deduplication key
const excludeHeaderNamesSet = new Set(excludeHeaderNames.map(name => name.toLowerCase()))
/**
* Map of pending requests for deduplication
* @type {Map<string, DeduplicationHandler>}
*/
const pendingRequests = new Map()
View on GitHub (pinned to 1b2de5e052)
Solutions
- Pass an array of header-name strings: `excludeHeaderNames: ['x-request-id', 'trace-id']`.
- Confirm you actually want key-exclusion semantics vs. full skip — use `skipHeaderNames` if the header should bypass deduplication entirely.
- Normalize single-string config values into arrays before passing.
Example fix
// before
deduplicate({ excludeHeaderNames: 'x-request-id' })
// after
deduplicate({ excludeHeaderNames: ['x-request-id'] }) Defensive patterns
Strategy: validation
Validate before calling
function toStringArray(v) {
if (v == null) return []
if (Array.isArray(v)) return v.map(String)
if (typeof v === 'string') return v.split(',').map(s => s.trim()).filter(Boolean)
throw new TypeError('expected string or array of header names')
} Type guard
function isHeaderNameArray(v) {
return Array.isArray(v) && v.every(x => typeof x === 'string')
} Prevention
- Distinguish excludeHeaderNames (key omission) from skipHeaderNames (full bypass).
- Pass header-name lists as arrays.
When it happens
Trigger: Passing `excludeHeaderNames: 'x-request-id'` as a string; passing a Set or object instead of an Array; passing a delimited string. The `Array.isArray(excludeHeaderNames)` guard fails before the Set is built.
Common situations: Confusing `excludeHeaderNames` (header omitted from the key) with `skipHeaderNames` (header disables dedup); passing a single header as a bare string; reusing a config value typed as a string. Often appears together with errors 300-302 from one malformed options object.
Related errors
- expected opts.skipHeaderNames to be an array, got ${typeof s
- expected opts.methods to be an array, got ${typeof methods}
- expected opts.maxBufferSize to be a positive finite number,
- expected type of opts to be an Object, got ${opts === null ?
- expected opts.methods to only contain safe HTTP methods, got
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/e37d29b0249a7f75.
Report an issue: GitHub.