{"record":{"id":"55e2ae5fa653215f","repo":"nodejs/node","slug":"maxredirections-must-be-a-positive-number","errorCode":null,"errorMessage":"maxRedirections must be a positive number","messagePattern":"maxRedirections must be a positive number","errorType":"exception","errorClass":"InvalidArgumentError","httpStatus":null,"severity":"error","filePath":"deps/undici/src/lib/handler/redirect-handler.js","lineNumber":14,"sourceCode":"'use strict'\n\nconst util = require('../core/util')\nconst assert = require('node:assert')\nconst { InvalidArgumentError } = require('../core/errors')\n\nconst redirectableStatusCodes = [300, 301, 302, 303, 307, 308]\n\nconst noop = () => {}\n\nclass RedirectHandler {\n  static buildDispatch (dispatcher, maxRedirections) {\n    if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) {\n      throw new InvalidArgumentError('maxRedirections must be a positive number')\n    }\n\n    const dispatch = dispatcher.dispatch.bind(dispatcher)\n    return (opts, originalHandler) => dispatch(opts, new RedirectHandler(dispatch, maxRedirections, opts, originalHandler))\n  }\n\n  constructor (dispatch, maxRedirections, opts, handler) {\n    if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) {\n      throw new InvalidArgumentError('maxRedirections must be a positive number')\n    }\n\n    if (opts.throwOnMaxRedirect != null && typeof opts.throwOnMaxRedirect !== 'boolean') {\n      throw new InvalidArgumentError('throwOnMaxRedirect must be a boolean')\n    }\n\n    this.dispatch = dispatch\n    this.location = null\n    const { maxRedirections: _, stripHeadersOnRedirect, stripHeadersOnCrossOriginRedirect, ...cleanOpts } = opts","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/undici/src/lib/handler/redirect-handler.js#L1-L32","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Coerce the value to a non-negative integer before passing it: Math.max(0, Math.trunc(Number(value))).","Pass null or undefined (or simply omit the option) if you do not want redirects followed.","Validate env-sourced values explicitly and fall back to a sensible default when parsing fails."],"exampleFix":"// before\nconst agent = new Agent({ maxRedirections: process.env.MAX_REDIRECTS })\n\n// after\nconst raw = Number.parseInt(process.env.MAX_REDIRECTS ?? '', 10)\nconst agent = new Agent({\n  maxRedirections: Number.isFinite(raw) ? Math.max(0, raw) : undefined\n})","handlingStrategy":"validation","validationCode":"function resolveMaxRedirections(value) {\n  if (value == null) return undefined\n  const n = Math.trunc(Number(value))\n  if (!Number.isFinite(n) || n < 0) {\n    throw new Error(`maxRedirections must be a non-negative integer, got ${String(value)}`)\n  }\n  return n\n}\n// usage: new Agent({ maxRedirections: resolveMaxRedirections(process.env.MAX_REDIRECTS) })","typeGuard":"function isMaxRedirections(v) {\n  return v == null || (Number.isInteger(v) && v >= 0)\n}","tryCatchPattern":"try { const agent = new Agent({ maxRedirections }) } catch (e) { if (e.code === 'UND_ERR_INVALID_ARG') { /* reconfigure with a sane default */ } else throw e }","preventionTips":["Never forward env/config strings directly; always Number() + isFinite guard.","Keep one normalization helper for maxRedirections and reuse it everywhere.","Omit the option when you do not need redirect following."],"tags":["undici","http","redirect","configuration","validation"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}