vercel/next.js · error

createRevalidateDuringRenderError (revalidate* called during

Error message

createRevalidateDuringRenderError (revalidate* called during render, route: ${store.route}, expression: ${expression})

What it means

Next.js throws createRevalidateDuringRenderError when revalidateTag/revalidatePath/updateTag is called during the render phase of a route. On-demand revalidation is a mutation of the cache and is only allowed in server actions, route handlers, or other non-render phases; calling it while a page/component is rendering would make cached output non-deterministic. The check first catches any workUnitStore in phase 'render' before dispatching on the store type.

Source

Thrown at packages/next/src/server/web/spec-extension/revalidate.ts:149

  return revalidate(tags, `revalidatePath(${JSON.stringify(originalPath)})`)
}

function revalidate(
  tags: string[],
  expression: string,
  profile?: string | CacheLifeConfig
) {
  const store = workAsyncStorage.getStore()
  if (!store || !store.incrementalCache) {
    throw new Error(
      `Invariant: static generation store missing in ${expression}`
    )
  }

  const workUnitStore = workUnitAsyncStorage.getStore()
  if (workUnitStore) {
    if (workUnitStore.phase === 'render') {
      throw createRevalidateDuringRenderError(store.route, expression)
    }

    switch (workUnitStore.type) {
      case 'cache':
      case 'private-cache':
      case 'unstable-cache':
      case 'generate-static-params':
        throw createRevalidateDuringRenderError(store.route, expression)
      case 'prerender':
      case 'prerender-runtime':
        // cacheComponents Prerender
        const error = new Error(
          `Route ${store.route} used ${expression} without first calling \`await connection()\`.`
        )
        return abortAndThrowOnSynchronousRequestDataAccess(
          store.route,
          expression,
          error,

View on GitHub (pinned to 258b1c1bc0)

Solutions

  1. Move the revalidate call into a Server Action ('use server' function) that is invoked by a form submit or event, then call revalidateTag/revalidatePath/updateTag there.
  2. Alternatively perform revalidation in a Route Handler (e.g. app/api/revalidate/route.ts) called via POST from the client or a webhook.
  3. If you only need fresh data while rendering, don't revalidate: read the data uncached or use await connection() to opt the segment into dynamic rendering.
  4. Audit component bodies for any imported revalidate* calls and ensure they only execute in action/handler contexts.

Example fix

// before
export default async function Page() {
  revalidateTag('posts') // throws: called during render
  return <PostList />
}

// after
async function refresh() {
  'use server'
  revalidateTag('posts')
}
export default function Page() {
  return <form action={refresh}><PostList /><button>Refresh</button></form>
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Guard before calling: only allow revalidation outside the render phase.
import { workUnitAsyncStorage } from 'next/dist/client/components/work-unit-async-storage' // internal: prefer a wrapper instead
function canRevalidateNow(): boolean {
  const store = workUnitAsyncStorage.getStore()
  return !store || store.phase !== 'render'
}

Type guard

function isRenderPhaseStore(store: unknown): store is { phase: 'render' } {
  return typeof store === 'object' && store !== null && (store as { phase?: string }).phase === 'render'
}

Try / catch

try {
  revalidateTag('posts')
} catch (e) {
  if (e instanceof Error && /Route .* used revalidate/i.test(e.message)) {
    console.error('revalidateTag cannot run during render — move it into a Server Action or Route Handler')
  } else throw e
}

Prevention

When it happens

Trigger: Calling revalidateTag('x'), revalidatePath('/path'), or updateTag('x') directly at the top level of a Server Component, page, layout, or any code executed synchronously during rendering (workUnitStore.phase === 'render'), including doing so inside a component's body instead of inside a server action or route handler.

Common situations: Calling revalidateTag inside a page to 'refresh' data after a mutation; calling it in a Server Component that also renders a form; triggering revalidation at module scope of a component file that runs during render; migrating from pages-router data-fetching patterns where such calls seemed to work; confusion between render-time code and server action handlers.

Related errors


AI-assisted analysis of vercel/next.js@258b1c1bc0 (2026-09-01). Data as JSON: /api/errors/b91092e0c75f5afb. Report an issue: GitHub.