nodejs/node · error · TypeError
expected opts.methods to only contain safe HTTP methods, got
Error message
expected opts.methods to only contain safe HTTP methods, got ${method} What it means
Thrown by the deduplicate interceptor when every element of the `methods` array is not a member of `util.safeHTTPMethods`, which is frozen to `['GET', 'HEAD', 'OPTIONS', 'TRACE']`. Deduplication shares a single response across N callers, which is only safe for methods defined as cacheable and side-effect-free. Including any non-safe method (POST, PUT, DELETE, PATCH, etc.) would let one caller trigger another's write, so the interceptor rejects them up front. It is a synchronous TypeError from the factory.
Source
Thrown at deps/undici/src/lib/interceptor/deduplicate.js:32
module.exports = (opts = {}) => {
const {
methods = ['GET'],
skipHeaderNames = [],
excludeHeaderNames = [],
maxBufferSize = 5 * 1024 * 1024
} = opts
if (typeof opts !== 'object' || opts === null) {
throw new TypeError(`expected type of opts to be an Object, got ${opts === null ? 'null' : typeof opts}`)
}
if (!Array.isArray(methods)) {
throw new TypeError(`expected opts.methods to be an array, got ${typeof methods}`)
}
for (const method of methods) {
if (!util.safeHTTPMethods.includes(method)) {
throw new TypeError(`expected opts.methods to only contain safe HTTP methods, got ${method}`)
}
}
if (!Array.isArray(skipHeaderNames)) {
throw new TypeError(`expected opts.skipHeaderNames to be an array, got ${typeof skipHeaderNames}`)
}
if (!Array.isArray(excludeHeaderNames)) {
throw new TypeError(`expected opts.excludeHeaderNames to be an array, got ${typeof excludeHeaderNames}`)
}
if (!Number.isFinite(maxBufferSize) || maxBufferSize <= 0) {
throw new TypeError(`expected opts.maxBufferSize to be a positive finite number, got ${maxBufferSize}`)
}
// Convert to lowercase Set for case-insensitive header matching
const skipHeaderNamesSet = new Set(skipHeaderNames.map(name => name.toLowerCase()))
View on GitHub (pinned to 1b2de5e052)
Solutions
- Restrict `methods` to uppercase entries from ['GET', 'HEAD', 'OPTIONS', 'TRACE'].
- If you passed lowercase verbs, uppercase them: `methods: opts.methods.map(m => m.toUpperCase())`.
- For write methods, drop deduplication and use a different strategy (request coalescing is unsafe for non-idempotent writes).
- If you genuinely need to coalesce a PUT/POST, reconsider — deduplication would corrupt the semantics of shared responses.
Example fix
// before
deduplicate({ methods: ['GET', 'POST'] })
deduplicate({ methods: ['get'] })
// after
deduplicate({ methods: ['GET'] })
deduplicate({ methods: ['GET', 'HEAD'] }) Defensive patterns
Strategy: type-guard
Validate before calling
const SAFE = new Set(['GET', 'HEAD', 'OPTIONS', 'TRACE'])
function validateMethods(methods) {
const up = methods.map(m => String(m).toUpperCase())
if (!up.every(m => SAFE.has(m))) {
throw new TypeError('methods must be subset of GET/HEAD/OPTIONS/TRACE')
}
return up
} Type guard
const SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS', 'TRACE']
function isSafeMethodArray(v) {
return Array.isArray(v) && v.every(m => typeof m === 'string' && SAFE_METHODS.includes(m.toUpperCase()))
} Prevention
- Uppercase method names before passing them.
- Remember deduplication is only valid for safe/idempotent verbs.
- Document the allowed set next to where you build the option.
When it happens
Trigger: Passing `methods: ['GET', 'POST']`, `methods: ['PUT']`, or any array containing a method not in `['GET','HEAD','OPTIONS','TRACE']`. Case matters: `methods: ['get']` also triggers it because the list contains uppercase entries and there is no normalization. Method names with trailing spaces or alternate casing fail the strict `.includes()`.
Common situations: Assuming all HTTP methods are deduplicable; trying to coalesce write/load-test traffic; copy-pasting a methods list from a caching layer that permits more methods; passing lowercase method names from a framework that lowercases verbs. The uppercase-only comparison is the most frequent surprise.
Related errors
- expected opts.methods to be an array, got ${typeof methods}
- expected type of opts to be an Object, got ${opts === null ?
- expected opts.skipHeaderNames to be an array, got ${typeof s
- expected opts.excludeHeaderNames to be an array, got ${typeo
- expected opts.maxBufferSize to be a positive finite number,
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/fea9186a142293ed.
Report an issue: GitHub.