vercel/next.js · error

Invalid "cacheHandlers" provided, expected an object e.g. {

Error message

Invalid "cacheHandlers" provided, expected an object e.g. { default: '/my-handler.js' }, received ${JSON.stringify(result.cacheHandlers)}

What it means

Thrown at config.ts:1443 when `cacheHandlers` is provided but `typeof result.cacheHandlers !== 'object'`. `cacheHandlers` maps cache-handler names to module paths (e.g. `{ default: '/my-handler.js' }`). Arrays are objects in JS and would pass this check but be caught by downstream key validation; non-object primitives (string, number, boolean) fail here.

Source

Thrown at packages/next/src/server/config.ts:1444

        const staticStaleTime = result.experimental.staleTimes?.static
        defaultCacheLifeProfile.stale =
          staticStaleTime ?? defaultConfig.experimental?.staleTimes?.static
      }
      if (defaultCacheLifeProfile.revalidate === undefined) {
        defaultCacheLifeProfile.revalidate = defaultDefault.revalidate
      }
      if (defaultCacheLifeProfile.expire === undefined) {
        defaultCacheLifeProfile.expire =
          result.expireTime ?? defaultDefault.expire
      }
    }
  }

  if (result.cacheHandlers) {
    const allowedHandlerNameRegex = /^[a-z-]+$/

    if (typeof result.cacheHandlers !== 'object') {
      throw new Error(
        `Invalid "cacheHandlers" provided, expected an object e.g. { default: '/my-handler.js' }, received ${JSON.stringify(result.cacheHandlers)}`
      )
    }

    const handlerKeys = Object.keys(result.cacheHandlers)
    const invalidHandlerItems: Array<{ key: string; reason: string }> = []

    for (const key of handlerKeys) {
      if (key === 'private') {
        invalidHandlerItems.push({
          key,
          reason:
            'The cache handler for "use cache: private" cannot be customized.',
        })
      } else if (!allowedHandlerNameRegex.test(key)) {
        invalidHandlerItems.push({
          key,
          reason: 'key must only use characters a-z and -',

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Provide `cacheHandlers` as an object mapping handler names to resolved file paths.
  2. Remove the `cacheHandlers` key if you are not customizing cache handlers.

Example fix

// before
module.exports = { cacheHandlers: '/my-handler.js' }
// after
module.exports = { cacheHandlers: { default: '/my-handler.js' } }
Defensive patterns

Strategy: type-guard

Validate before calling

if (cacheHandlers !== undefined && (typeof cacheHandlers !== 'object' || Array.isArray(cacheHandlers))) {
  throw new Error('cacheHandlers must be a plain object');
}

Type guard

function isHandlerMap(x: unknown): x is Record<string, string> {
  return typeof x === 'object' && x !== null && !Array.isArray(x);
}

Prevention

When it happens

Trigger: `cacheHandlers: '/my-handler.js'` (string); `cacheHandlers: ['default']` (array — passes here but fails key validation); `cacheHandlers: 42`.

Common situations: Misreading the option as a path string; migrating from an older array-based custom-handler config.

Related errors


AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06). Data as JSON: /api/errors/899b631ccdbcacff. Report an issue: GitHub.