nodejs/node · error · TypeError

callback must be a function

Error message

callback must be a function

What it means

Thrown by the CacheRevalidationHandler constructor when callback is not a function. The handler invokes callback(success, context, statusCode, headers) to report whether a cached entry is still valid after a revalidation round-trip (e.g. HTTP 304); a non-function callback would silently drop that signal. Note this throws TypeError, not InvalidArgumentError.

Source

Thrown at deps/undici/src/lib/handler/cache-revalidation-handler.js:45

   * @type {(import('../../types/dispatcher.d.ts').default.DispatchHandler)}
   */
  #handler

  #context

  /**
   * @type {boolean}
   */
  #allowErrorStatusCodes

  /**
   * @param {(success: boolean, context?: any, statusCode?: number, headers?: import('../../types/header.d.ts').IncomingHttpHeaders) => void} callback Function to call if the cached value is valid
   * @param {import('../../types/dispatcher.d.ts').default.DispatchHandlers} handler
   * @param {boolean} allowErrorStatusCodes
   */
  constructor (callback, handler, allowErrorStatusCodes) {
    if (typeof callback !== 'function') {
      throw new TypeError('callback must be a function')
    }

    this.#callback = callback
    this.#handler = handler
    this.#allowErrorStatusCodes = allowErrorStatusCodes
  }

  onRequestStart (_, context) {
    this.#successful = false
    this.#context = context
  }

  onRequestUpgrade (controller, statusCode, headers, socket) {
    this.#handler.onRequestUpgrade?.(controller, statusCode, headers, socket)
  }

  onResponseStart (
    controller,

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Pass a function as the first argument: (success, context, statusCode, headers) => { ... }.
  2. Double-check argument order: callback first, then the downstream DispatchHandler.
  3. If you do not need revalidation feedback, pass a no-op () => {} rather than omitting it.
  4. Type-check the callback in your cache wrapper before constructing the handler.

Example fix

// before
new CacheRevalidationHandler(downstreamHandler)
// after
new CacheRevalidationHandler((ok, ctx, code, hdrs) => { if (!ok) evict(ctx) }, downstreamHandler)
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof callback !== 'function') {
  throw new TypeError('CacheRevalidationHandler requires a function callback as its first argument')
}
new CacheRevalidationHandler(callback, handler)

Type guard

function isCallback(v) { return typeof v === 'function' }

Prevention

When it happens

Trigger: Constructing new CacheRevalidationHandler(null, handler), new CacheRevalidationHandler({}, handler), or omitting the first argument. The first parameter must be the revalidation-result callback.

Common situations: Passing the wrapped handler as the first arg by mistake; passing a config object where the callback was expected; refactoring that swapped argument order; building a custom cache layer that forgets the callback.

Related errors


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