nodejs/node · error · TypeError
expected ${name} to be an array or undefined, got ${typeof o
Error message
expected ${name} to be an array or undefined, got ${typeof origins} What it means
Thrown by assertCacheOrigins in the cache() interceptor factory. The origins option (a whitelist of origins eligible for caching) must be undefined (cache all origins) or an array of strings/RegExps. Passing any other type (a single string, an object, a number, a Set) is rejected.
Source
Thrown at deps/undici/src/lib/interceptor/cache.js:20
const assert = require('node:assert')
const { Readable } = require('node:stream')
const util = require('../core/util')
const CacheHandler = require('../handler/cache-handler')
const MemoryCacheStore = require('../cache/memory-cache-store')
const CacheRevalidationHandler = require('../handler/cache-revalidation-handler')
const { assertCacheStore, assertCacheMethods, makeCacheKey, normalizeHeaders, parseCacheControlHeader, isInvalidOrWildcardVaryHeader } = require('../util/cache.js')
const { AbortError } = require('../core/errors.js')
const { parseHttpDate } = require('../util/date.js')
/**
* @param {(string | RegExp)[] | undefined} origins
* @param {string} name
*/
function assertCacheOrigins (origins, name) {
if (origins === undefined) return
if (!Array.isArray(origins)) {
throw new TypeError(`expected ${name} to be an array or undefined, got ${typeof origins}`)
}
for (let i = 0; i < origins.length; i++) {
const origin = origins[i]
if (typeof origin !== 'string' && !(origin instanceof RegExp)) {
throw new TypeError(`expected ${name}[${i}] to be a string or RegExp, got ${typeof origin}`)
}
}
}
const nop = () => {}
function trimOWS (value) {
return value.replace(/^[\t ]+|[\t ]+$/g, '')
}
function arrayIncludes (array, value) {
for (let i = 0; i < array.length; i++) {
if (array[i] === value) {View on GitHub (pinned to 1b2de5e052)
Solutions
- Pass origins as an array: ['https://a.com', /https:\/\/.*\.internal/], or omit it to cache all origins.
- Convert single strings: ['https://a.com']; convert Sets: Array.from(set).
- Validate the option at the config boundary before composing the interceptor.
Example fix
// before
client.compose(interceptors.cache({ origins: 'https://api.example.com' }))
// after
client.compose(interceptors.cache({ origins: ['https://api.example.com'] })) Defensive patterns
Strategy: validation
Validate before calling
function normalizeOrigins(v) {
if (v == null) return undefined
return Array.isArray(v) ? v : [v]
} Type guard
function isOrigins(v) { return v == null || (Array.isArray(v) && v.every(o => typeof o === 'string' || o instanceof RegExp)) } Try / catch
try { client.compose(interceptors.cache({ origins })) } catch (e) { if (e instanceof TypeError && /to be an array/.test(e.message)) { client.compose(interceptors.cache({ origins: Array.isArray(origins) ? origins : [origins] })) } else throw e } Prevention
- Always pass origins as an array of strings/RegExps.
- Omit the option to cache all origins.
- Convert single strings/Sets at the config boundary.
When it happens
Trigger: Calling interceptors.cache({ origins: ... }) with origins as a string ('https://a.com'), a Set, an object map, or any non-array value.
Common situations: Configuring the cache interceptor from a config file that used a single string or a Set; copy-pasting an example that used a different shape; TypeScript where the type was widened.
Related errors
- 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
- expected type of opts to be an Object, got ${opts === null ?
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/ca288164d70ca70a.
Report an issue: GitHub.