nodejs/node · error · UndiciError
UND_ERR
UND_ERR
Error message
1 interceptor is pending:\n\n${pendingInterceptorsFormatter.format(pending)} What it means
Thrown by `MockAgent.assertNoPendingInterceptors()` (an `UndiciError`, generic code `UND_ERR`) when exactly one mocked interceptor was registered but never matched/consumed by a real dispatch. In test suites this assertion verifies that every mocked route was actually exercised — a pending interceptor usually means a typo in the path/method, a wrong origin, or dead test setup. The message includes a formatted description of the unmatched interceptor.
Source
Thrown at deps/undici/src/lib/mock/mock-agent.js:224
return this[kNetConnect]
}
pendingInterceptors () {
const mockAgentClients = this[kClients]
return Array.from(mockAgentClients.entries())
.flatMap(([origin, dispatcher]) => dispatcher[kDispatches].map(dispatch => ({ ...dispatch, origin })))
.filter(({ pending }) => pending)
}
assertNoPendingInterceptors ({ pendingInterceptorsFormatter = new PendingInterceptorsFormatter() } = {}) {
const pending = this.pendingInterceptors()
if (pending.length === 0) {
return
}
throw new UndiciError(
pending.length === 1
? `1 interceptor is pending:\n\n${pendingInterceptorsFormatter.format(pending)}`.trim()
: `${pending.length} interceptors are pending:\n\n${pendingInterceptorsFormatter.format(pending)}`.trim()
)
}
}
module.exports = MockAgent
View on GitHub (pinned to 1b2de5e052)
Solutions
- Compare the intercept's `path`/`method`/`origin` against the actual request your code makes — use `mockAgent.getCallHistory()` if call history is enabled.
- Ensure the code under test actually runs and reaches the mocked dispatch (no early return, no swallowed error).
- If the interceptor is intentionally unused, remove it or split it into its own test.
- Check for trailing-slash and protocol/port mismatches; consider enabling `ignoreTrailingSlash` on the MockAgent.
Example fix
// before
mockAgent.get('https://api.test').intercept({ path: '/user', method: 'GET' }).reply(200)
await fetch('https://api.test/users') // typo: /user vs /users
mockAgent.assertNoPendingInterceptors() // throws: 1 pending
// after
mockAgent.get('https://api.test').intercept({ path: '/users', method: 'GET' }).reply(200)
await fetch('https://api.test/users')
mockAgent.assertNoPendingInterceptors() // passes Defensive patterns
Strategy: validation
Validate before calling
function assertAllInterceptorsConsumed(mockAgent) {
const pending = mockAgent.pendingInterceptors()
if (pending.length === 1) {
const p = pending[0]
throw new Error(`Unmatched intercept: ${p.method} ${p.origin}${p.path}`)
}
} Try / catch
try {
mockAgent.assertNoPendingInterceptors()
} catch (err) {
// err lists the unmatched interceptor; reconcile path/method/origin
throw err
} Prevention
- Reconcile intercept path/method/origin against the real request URL.
- Enable call history to inspect what was actually dispatched.
- Consider ignoreTrailingSlash to absorb trailing-slash mismatches.
When it happens
Trigger: Registering `mockAgent.get(origin).intercept({ path: '/users', method: 'GET' }).reply(200)` but the code under test calls `/user` (typo), a different origin, or `POST`. After the test, `assertNoPendingInterceptors()` finds the one unmatched entry and throws. Singular form is chosen because `pending.length === 1`.
Common situations: Path/method typos between the intercept declaration and the code under test; origin mismatch (trailing slash, protocol, port); the code under test not being invoked (skipped branch, early throw); intercept declared on the wrong MockClient/MockPool; query-string differences when matching is strict.
Related errors
- UND_ERR_INVALID_ARG
- UND_ERR_INVALID_ARG
- invalid interceptor, expected function received ${typeof int
- invalid interceptor
- expected ${name} to be an array or undefined, got ${typeof o
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/917bcd1de843a044.
Report an issue: GitHub.