nodejs/node · error · InvalidArgumentError
throwOnMaxRedirect must be a boolean
Error message
throwOnMaxRedirect must be a boolean
What it means
Thrown from the RedirectHandler constructor when opts.throwOnMaxRedirect is present but is not a boolean. throwOnMaxRedirect is a per-request flag that, when true, makes the handler throw instead of silently stopping once maxRedirections is exhausted. It must be a real boolean (or null/undefined to leave it unset); truthy/falsy values like 'true', 1, 0, or 'yes' are rejected because typeof is checked.
Source
Thrown at deps/undici/src/lib/handler/redirect-handler.js:27
const noop = () => {}
class RedirectHandler {
static buildDispatch (dispatcher, maxRedirections) {
if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) {
throw new InvalidArgumentError('maxRedirections must be a positive number')
}
const dispatch = dispatcher.dispatch.bind(dispatcher)
return (opts, originalHandler) => dispatch(opts, new RedirectHandler(dispatch, maxRedirections, opts, originalHandler))
}
constructor (dispatch, maxRedirections, opts, handler) {
if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) {
throw new InvalidArgumentError('maxRedirections must be a positive number')
}
if (opts.throwOnMaxRedirect != null && typeof opts.throwOnMaxRedirect !== 'boolean') {
throw new InvalidArgumentError('throwOnMaxRedirect must be a boolean')
}
this.dispatch = dispatch
this.location = null
const { maxRedirections: _, stripHeadersOnRedirect, stripHeadersOnCrossOriginRedirect, ...cleanOpts } = opts
this.opts = cleanOpts // opts must be a copy, exclude maxRedirections
this.opts.body = util.wrapRequestBody(this.opts.body)
this.stripHeadersOnRedirect = normalizeStripHeaders(stripHeadersOnRedirect, 'stripHeadersOnRedirect')
this.stripHeadersOnCrossOriginRedirect = normalizeStripHeaders(stripHeadersOnCrossOriginRedirect, 'stripHeadersOnCrossOriginRedirect')
this.maxRedirections = maxRedirections
this.handler = handler
this.history = []
}
onRequestStart (controller, context) {
this.handler.onRequestStart?.(controller, { ...context, history: this.history })
}
View on GitHub (pinned to 1b2de5e052)
Solutions
- Coerce to a strict boolean before passing: throwOnMaxRedirect: Boolean(value) (or only set it when value is already boolean).
- Omit the option entirely if you do not need throw-on-max behavior; it defaults to unset.
- Validate incoming config with a boolean schema field (e.g. zod/ajv) at the trust boundary.
Example fix
// before
await client.request({ path, method: 'GET', throwOnMaxRedirect: req.query.strict })
// after
const strict = req.query.strict === 'true' || req.query.strict === true
await client.request({ path, method: 'GET', throwOnMaxRedirect: strict }) Defensive patterns
Strategy: type-guard
Validate before calling
function strictBool(v) { return typeof v === 'boolean' ? v : undefined } Type guard
function isBool(v) { return v == null || typeof v === 'boolean' } Try / catch
try { await client.request({ throwOnMaxRedirect: flag }) } catch (e) { if (e.code === 'UND_ERR_INVALID_ARG') { await client.request({ /* drop throwOnMaxRedirect */ }) } else throw e } Prevention
- Coerce with Boolean() at the config boundary.
- Reject 'true'/'false' strings from query params explicitly.
- Omit the option when you do not need throw behavior.
When it happens
Trigger: Passing throwOnMaxRedirect as a string ('true'/'false'), a number (1/0), or any non-boolean truthy/falsy value in per-request dispatch opts or in the request options of an Agent configured with redirects.
Common situations: Flags parsed from query strings, headers, or JSON config arriving as strings; code that assumes 'throw on truthy' semantics; copying a value from a loosely-typed settings object.
Related errors
- maxRedirections must be a positive number
- ${optionName} must be an array
- ${optionName} must contain header names
- expected ${name} to be an array or undefined, got ${typeof o
- expected ${name}[${i}] to be a string or RegExp, got ${typeo
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/8d323558d4373bb1.
Report an issue: GitHub.