nodejs/node · error · MaxOriginsReachedError
UND_ERR_MAX_ORIGINS_REACHED
UND_ERR_MAX_ORIGINS_REACHED
Error message
Maximum allowed origins reached
What it means
Thrown inside Agent's [kDispatch] as a MaxOriginsReachedError (code UND_ERR_MAX_ORIGINS_REACHED). The check is: this[kOrigins].size >= this[kOptions].maxOrigins AND the current origin is not already tracked. The Agent refuses to silently evict or grow beyond the configured cap, so a brand-new origin past the limit is rejected outright.
Source
Thrown at deps/undici/src/lib/dispatcher/agent.js:86
for (const dispatcher of this[kClients].values()) {
ret += dispatcher[kRunning]
}
return ret
}
[kDispatch] (opts, handler) {
let origin
if (opts.origin && (typeof opts.origin === 'string' || opts.origin instanceof URL)) {
origin = String(opts.origin)
} else {
throw new InvalidArgumentError('opts.origin must be a non-empty string or URL.')
}
const allowH2 = opts.allowH2 ?? this[kOptions].allowH2
const key = allowH2 === false ? `${origin}#http1-only` : origin
if (this[kOrigins].size >= this[kOptions].maxOrigins && !this[kOrigins].has(origin)) {
throw new MaxOriginsReachedError()
}
let dispatcher = this[kClients].get(key)
if (!dispatcher) {
dispatcher = this[kFactory](opts.origin, allowH2 === false
? { ...this[kOptions], allowH2: false }
: this[kOptions])
const closeClientIfUnused = () => {
if (this[kClients].get(key) !== dispatcher) {
return
}
if (dispatcher[kConnected] > 0 || dispatcher[kBusy]) {
return
}
this[kClients].delete(key)View on GitHub (pinned to 1b2de5e052)
Solutions
- Raise maxOrigins to cover the expected origin cardinality (or omit it for Infinity).
- Pool repeated origins so they count once — make sure the origin string is normalized (trailing slash, lowercase host).
- Catch MaxOriginsReachedError and fall back to a fresh Client/Pool for overflow origins.
Example fix
// before
const agent = new Agent({ maxOrigins: 2 })
await agent.request({ origin: 'https://a.com', method: 'GET', path: '/' })
await agent.request({ origin: 'https://b.com', method: 'GET', path: '/' })
await agent.request({ origin: 'https://c.com', method: 'GET', path: '/' }) // throws
// after
const agent = new Agent({ maxOrigins: Infinity }) Defensive patterns
Strategy: fallback
Validate before calling
function boundedDispatch(agent, opts, handler, overflowPool) {
try {
return agent.dispatch(opts, handler)
} catch (e) {
if (e.code === 'UND_ERR_MAX_ORIGINS_REACHED') return overflowPool.dispatch(opts, handler)
throw e
}
} Type guard
const isMaxOriginsError = (e) => e?.code === 'UND_ERR_MAX_ORIGINS_REACHED'
Try / catch
try {
await agent.request({ origin, method, path })
} catch (e) {
if (e.code === 'UND_ERR_MAX_ORIGINS_REACHED') {
// raise maxOrigins or route via a fallback Client
} else throw e
} Prevention
- Size maxOrigins to your real origin cardinality plus headroom.
- Normalize origin strings (lowercase host, strip trailing slash) so duplicates count once.
When it happens
Trigger: new Agent({ maxOrigins: 3 }) then dispatching to four DISTINCT origins (the fourth, never-seen-before origin triggers the throw); a crawler hitting many hosts through a capped Agent.
Common situations: A polyglot client pointed at many microservices through one low-capped Agent; raising traffic to include more origins than the configured cap; mis-tuning maxOrigins down for memory and then seeing new hosts fail.
Related errors
- SqliteCacheStore options.maxEntrySize must be less than 2gb
- UND_ERR_INVALID_ARG
- UND_ERR_BPL_MISSING_UPSTREAM
- Redirect loop detected. Cannot redirect to ${origin}. This t
- UND_ERR_INVALID_ARG
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/f3afba85de7da502.
Report an issue: GitHub.