nodejs/node · error · InvalidArgumentError

maxRedirections must be a positive number

Error message

maxRedirections must be a positive number

What it means

Thrown by undici's RedirectHandler.buildDispatch when wiring up the redirect-dispatch wrapper. The maxRedirections option (set via new Agent({ maxRedirections }), the redirect() interceptor, or per-request opts) must be null/undefined or a non-negative integer. Note the message says 'positive' but 0 is actually accepted (it disables following redirects); floats, negatives, strings, Infinity, and NaN are rejected.

Source

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

'use strict'

const util = require('../core/util')
const assert = require('node:assert')
const { InvalidArgumentError } = require('../core/errors')

const redirectableStatusCodes = [300, 301, 302, 303, 307, 308]

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

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Coerce the value to a non-negative integer before passing it: Math.max(0, Math.trunc(Number(value))).
  2. Pass null or undefined (or simply omit the option) if you do not want redirects followed.
  3. Validate env-sourced values explicitly and fall back to a sensible default when parsing fails.

Example fix

// before
const agent = new Agent({ maxRedirections: process.env.MAX_REDIRECTS })

// after
const raw = Number.parseInt(process.env.MAX_REDIRECTS ?? '', 10)
const agent = new Agent({
  maxRedirections: Number.isFinite(raw) ? Math.max(0, raw) : undefined
})
Defensive patterns

Strategy: validation

Validate before calling

function resolveMaxRedirections(value) {
  if (value == null) return undefined
  const n = Math.trunc(Number(value))
  if (!Number.isFinite(n) || n < 0) {
    throw new Error(`maxRedirections must be a non-negative integer, got ${String(value)}`)
  }
  return n
}
// usage: new Agent({ maxRedirections: resolveMaxRedirections(process.env.MAX_REDIRECTS) })

Type guard

function isMaxRedirections(v) {
  return v == null || (Number.isInteger(v) && v >= 0)
}

Try / catch

try { const agent = new Agent({ maxRedirections }) } catch (e) { if (e.code === 'UND_ERR_INVALID_ARG') { /* reconfigure with a sane default */ } else throw e }

Prevention

When it happens

Trigger: Passing maxRedirections as a string (e.g. read straight from an env var), a float like 1.5, a negative number, or NaN when constructing an Agent/Pool/Client with redirects enabled, or when composing the redirect() interceptor.

Common situations: Reading maxRedirections from process.env or a YAML/JSON config without coercing to a Number; TypeScript code where a string|number union slips through; passing parseInt() result that yielded NaN on bad input.

Related errors


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