nodejs/node · error · TypeError

expected ${name}[${i}] to be a string or RegExp, got ${typeo

Error message

expected ${name}[${i}] to be a string or RegExp, got ${typeof origin}

What it means

Thrown by assertCacheOrigins when the origins array contains an element that is neither a string nor a RegExp. Each entry must be an exact origin string (compared case-insensitively) or a RegExp tested against the lowercase origin. Numbers, objects, null, booleans, or URL objects are rejected.

Source

Thrown at deps/undici/src/lib/interceptor/cache.js:25

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) {
      return true
    }
  }

  return false

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Use plain origin strings or RegExps only; convert URL objects via url.origin.
  2. Filter the source list: origins.filter(o => typeof o === 'string' || o instanceof RegExp).
  3. Omit the origins option when the filtered list is empty.

Example fix

// before
client.compose(interceptors.cache({ origins: [new URL('https://api.example.com')] }))

// after
client.compose(interceptors.cache({
  origins: ['https://api.example.com']
}))
Defensive patterns

Strategy: type-guard

Validate before calling

function cleanOrigins(arr) {
  return Array.isArray(arr) ? arr.filter(o => typeof o === 'string' || o instanceof RegExp) : undefined
}

Type guard

function isOriginEntry(o) { return typeof o === 'string' || o instanceof RegExp }

Try / catch

try { client.compose(interceptors.cache({ origins: arr })) } catch (e) { if (e instanceof TypeError && /string or RegExp/.test(e.message)) { client.compose(interceptors.cache({ origins: arr.filter(o => typeof o === 'string' || o instanceof RegExp) })) } else throw e }

Prevention

When it happens

Trigger: Passing origins: [new URL('https://a.com')] (URL object), ['https://a.com', 42], or origins: [null]; building the array from mixed-type config without filtering.

Common situations: Using URL objects instead of .toString()/.origin strings; optional entries pushed as null/undefined; JSON config with mixed types.

Related errors


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