{"record":{"id":"d62a9048c6e9b55d","repo":"vercel/next.js","slug":"page-with-dynamic-error-encountered-dynamic-da","errorCode":null,"errorMessage":"Page with dynamic = \"error\" encountered dynamic data method on ${path}.","messagePattern":"Page with dynamic = \"error\" encountered dynamic data method on (.+?)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/next/src/export/routes/app-page.ts","lineNumber":115,"sourceCode":"      flightData,\n      cacheControl = { revalidate: false, expire: undefined },\n      postponed,\n      fetchTags,\n      fetchMetrics,\n      segmentData,\n      prefetchHints,\n      renderResumeDataCache,\n      hasPendingUi,\n    } = metadata\n\n    // Ensure we don't postpone without having PPR enabled.\n    if (postponed && !renderOpts.experimental.isRoutePPREnabled) {\n      throw new Error('Invariant: page postponed without PPR being enabled')\n    }\n\n    if (cacheControl.revalidate === 0) {\n      if (isDynamicError) {\n        throw new Error(\n          `Page with dynamic = \"error\" encountered dynamic data method on ${path}.`\n        )\n      }\n      const { staticBailoutInfo = {} } = metadata\n\n      if (debugOutput && staticBailoutInfo?.description) {\n        logDynamicUsageWarning({\n          path,\n          description: staticBailoutInfo.description,\n          stack: staticBailoutInfo.stack,\n        })\n      }\n\n      return { cacheControl, fetchMetrics }\n    }\n\n    // If page data isn't available, it means that the page couldn't be rendered\n    // properly so long as we don't have unknown route params. When a route doesn't","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/vercel/next.js/blob/0ae8c72462952df163f1b1e0726641bc5b40dc93/packages/next/src/export/routes/app-page.ts#L97-L133","documentation":"Thrown in the App Router export path when a route declared `export const dynamic = 'error'` (a.k.a. the page opts out of dynamic rendering) yet, during prerender, the render result reports cacheControl.revalidate === 0 AND isDynamicError is true. The dynamic='error' contract promises the route is fully static; the framework detects that a dynamic data method (cookies(), headers(), draftMode(), searchParams sync access, request.time, etc.) was invoked and refuses to silently fall back to dynamic rendering.","triggerScenarios":"An app-router page or layout exports `const dynamic = 'error'` and then calls cookies(), headers(), searchParams, or another dynamic request API during render or in a generateMetadata/generateStaticParams helper. Triggered at build time during prerender of that route.","commonSituations":"Developers copy a server component that reads cookies() for personalization but also leave `dynamic = 'error'` from a template. Or a third-party dependency (auth, A/B testing) reaches into request storage. Upgrading Next.js can newly flag a previously-tolerated access because the dynamic-usage detector tightened.","solutions":["Remove `export const dynamic = 'error'` from the route if it genuinely needs request data, or switch to `dynamic = 'force-dynamic'`.","Push the dynamic access (cookies/headers/searchParams) into a child segment or Suspense boundary that is allowed to be dynamic, keeping the parent static.","If the dynamic call is unintentional, locate it via the build's 'reason' log and replace it with a static equivalent (e.g. read from generateStaticParams params, not from cookies).","Verify no imported library implicitly accesses request storage; wrap it behind a client component or a 'use cache' boundary."],"exampleFix":"// before — app/page.tsx\nimport { cookies } from 'next/headers'\nexport const dynamic = 'error'\nexport default function Page() {\n  const theme = cookies().get('theme')?.value\n  return <p>{theme}</p>\n}\n// after — drop the conflicting contract\nimport { cookies } from 'next/headers'\nexport const dynamic = 'force-dynamic'\nexport default function Page() {\n  const theme = cookies().get('theme')?.value\n  return <p>{theme}</p>\n}","handlingStrategy":"validation","validationCode":"// Scan the route module's source for dynamic APIs before declaring dynamic='error'\nconst DYNAMIC_APIS = ['cookies(', 'headers(', 'draftMode(', 'searchParams', 'request\\.']\nfunction safeToUseDynamicError(source: string): boolean {\n  return !DYNAMIC_APIS.some((re) => new RegExp(re).test(source))\n}","typeGuard":"// runtime check: a page declaring dynamic='error' must not touch request storage\nimport { isCallerDynamicAccessSupported } from './checks'\nfunction assertStaticContract(usesDynamic: boolean, declared: string) {\n  if (usesDynamic && declared === 'error') {\n    throw new Error('Route uses dynamic APIs but declares dynamic=\"error\"')\n  }\n}","tryCatchPattern":"// Not catchable in user code — runs at build time.\n// Instead, gate the contract with a CI grep:\n//   rg -n \"cookies\\(|headers\\(\" app/**/page.tsx | xargs grep -l \"dynamic.*error\"","preventionTips":["Only set dynamic='error' on routes you have audited for cookies/headers/searchParams usage.","Keep dynamic data access in dedicated child segments behind Suspense.","Add an ESLint custom rule banning cookies()/headers() in routes that export dynamic='error'.","Review third-party imports for implicit request-storage access."],"tags":["app-router","dynamic-rendering","build","ssr"],"analyzedSha":"0ae8c72462952df163f1b1e0726641bc5b40dc93","analyzedAt":"2026-08-06T19:44:29.143Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}