nodejs/node · error · InvalidArgumentError

${optionName} must contain header names

Error message

${optionName} must contain header names

What it means

Thrown by normalizeStripHeaders when the stripHeadersOnRedirect / stripHeadersOnCrossOriginRedirect array contains an element that is not a string. Each entry must be a header-name string; numbers, booleans, objects, null, or undefined elements are rejected.

Source

Thrown at deps/undici/src/lib/handler/redirect-handler.js:191

    return name === 'authorization' || name === 'cookie' || name === 'proxy-authorization'
  }
  return false
}

// https://tools.ietf.org/html/rfc7231#section-6.4
function normalizeStripHeaders (headers, optionName) {
  if (headers == null) {
    return null
  }

  if (!Array.isArray(headers)) {
    throw new InvalidArgumentError(`${optionName} must be an array`)
  }

  const normalized = new Set()
  for (const header of headers) {
    if (typeof header !== 'string') {
      throw new InvalidArgumentError(`${optionName} must contain header names`)
    }

    normalized.add(util.headerNameToString(header))
  }
  return normalized
}

function cleanRequestHeaders (headers, removeContent, unknownOrigin, stripHeaders, stripHeadersOnCrossOrigin) {
  const ret = []
  if (Array.isArray(headers)) {
    for (let i = 0; i < headers.length; i += 2) {
      if (!shouldRemoveHeader(headers[i], removeContent, unknownOrigin, stripHeaders, stripHeadersOnCrossOrigin)) {
        ret.push(headers[i], headers[i + 1])
      }
    }
  } else if (headers && typeof headers === 'object') {
    const entries = util.hasSafeIterator(headers) ? headers : Object.entries(headers)

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Ensure every element is a string; filter the source list: names.filter(n => typeof n === 'string').
  2. Build the option only from strongly-typed string arrays at the configuration boundary.
  3. Default to omitting the option when the filtered list is empty.

Example fix

// before
const strip = ['authorization', traceId ?? undefined]
new Agent({ maxRedirections: 5, stripHeadersOnRedirect: strip })

// after
const strip = ['authorization', traceId].filter(h => typeof h === 'string')
new Agent({ maxRedirections: 5, stripHeadersOnRedirect: strip.length ? strip : undefined })
Defensive patterns

Strategy: type-guard

Validate before calling

function cleanStripHeaders(arr) {
  return Array.isArray(arr) ? arr.filter(h => typeof h === 'string') : undefined
}

Type guard

function isStringArray(v) { return Array.isArray(v) && v.every(x => typeof x === 'string') }

Try / catch

try { new Agent({ stripHeadersOnRedirect: arr }) } catch (e) { if (e.code === 'UND_ERR_INVALID_ARG') { new Agent({ stripHeadersOnRedirect: arr.filter(h => typeof h === 'string') }) } else throw e }

Prevention

When it happens

Trigger: Passing an array like ['authorization', 42] or ['x-trace', undefined] for stripHeadersOnRedirect / stripHeadersOnCrossOriginRedirect; building the array dynamically without filtering non-strings.

Common situations: Injecting a numeric or boolean config value into a header list; optional header names conditionally pushed as undefined; data sourced from JSON with mixed types.

Related errors


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