{"record":{"id":"b91092e0c75f5afb","repo":"vercel/next.js","slug":"createrevalidateduringrendererror-revalidate-cal","errorCode":null,"errorMessage":"createRevalidateDuringRenderError (revalidate* called during render, route: ${store.route}, expression: ${expression})","messagePattern":"createRevalidateDuringRenderError \\(revalidate\\* called during render, route: (.+?), expression: (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/next/src/server/web/spec-extension/revalidate.ts","lineNumber":149,"sourceCode":"  return revalidate(tags, `revalidatePath(${JSON.stringify(originalPath)})`)\n}\n\nfunction revalidate(\n  tags: string[],\n  expression: string,\n  profile?: string | CacheLifeConfig\n) {\n  const store = workAsyncStorage.getStore()\n  if (!store || !store.incrementalCache) {\n    throw new Error(\n      `Invariant: static generation store missing in ${expression}`\n    )\n  }\n\n  const workUnitStore = workUnitAsyncStorage.getStore()\n  if (workUnitStore) {\n    if (workUnitStore.phase === 'render') {\n      throw createRevalidateDuringRenderError(store.route, expression)\n    }\n\n    switch (workUnitStore.type) {\n      case 'cache':\n      case 'private-cache':\n      case 'unstable-cache':\n      case 'generate-static-params':\n        throw createRevalidateDuringRenderError(store.route, expression)\n      case 'prerender':\n      case 'prerender-runtime':\n        // cacheComponents Prerender\n        const error = new Error(\n          `Route ${store.route} used ${expression} without first calling \\`await connection()\\`.`\n        )\n        return abortAndThrowOnSynchronousRequestDataAccess(\n          store.route,\n          expression,\n          error,","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/vercel/next.js/blob/258b1c1bc05f7099816b88f70b7b3422b24a4b8d/packages/next/src/server/web/spec-extension/revalidate.ts#L131-L167","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","Alternatively perform revalidation in a Route Handler (e.g. app/api/revalidate/route.ts) called via POST from the client or a webhook.","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.","Audit component bodies for any imported revalidate* calls and ensure they only execute in action/handler contexts."],"exampleFix":"// before\nexport default async function Page() {\n  revalidateTag('posts') // throws: called during render\n  return <PostList />\n}\n\n// after\nasync function refresh() {\n  'use server'\n  revalidateTag('posts')\n}\nexport default function Page() {\n  return <form action={refresh}><PostList /><button>Refresh</button></form>\n}","handlingStrategy":"try-catch","validationCode":"// Guard before calling: only allow revalidation outside the render phase.\nimport { workUnitAsyncStorage } from 'next/dist/client/components/work-unit-async-storage' // internal: prefer a wrapper instead\nfunction canRevalidateNow(): boolean {\n  const store = workUnitAsyncStorage.getStore()\n  return !store || store.phase !== 'render'\n}","typeGuard":"function isRenderPhaseStore(store: unknown): store is { phase: 'render' } {\n  return typeof store === 'object' && store !== null && (store as { phase?: string }).phase === 'render'\n}","tryCatchPattern":"try {\n  revalidateTag('posts')\n} catch (e) {\n  if (e instanceof Error && /Route .* used revalidate/i.test(e.message)) {\n    console.error('revalidateTag cannot run during render — move it into a Server Action or Route Handler')\n  } else throw e\n}","preventionTips":["Only call revalidateTag/revalidatePath/updateTag inside 'use server' actions or Route Handlers — never in component bodies.","Add an ESLint rule or code-review checklist flagging revalidate* imports outside server-action/handler files.","Handle mutations in dedicated server actions, and keep render functions purely read-only.","If fresh data is needed at render time, use await connection()/dynamic rendering instead of revalidation."],"tags":["revalidation","server-actions","render-phase","nextjs"],"backgroundTag":"revalidate-during-render","analyzedSha":"258b1c1bc05f7099816b88f70b7b3422b24a4b8d","analyzedAt":"2026-09-01T03:35:59.642Z","contentChangedAt":"2026-09-01T03:35:59.642Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}