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

  1. Restrict `methods` to uppercase entries from ['GET', 'HEAD', 'OPTIONS', 'TRACE'].
  2. If you passed lowercase verbs, uppercase them: `methods: opts.methods.map(m => m.toUpperCase())`.
  3. For write methods, drop deduplication and use a different strategy (request coalescing is unsafe for non-idempotent writes).
  4. 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

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


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