{"record":{"id":"ab41482c692de754","repo":"vercel/next.js","slug":"expression","errorCode":null,"errorMessage":"${expression}","messagePattern":"\\$\\{expression\\}","errorType":"exception","errorClass":"BailoutToCSRError","httpStatus":null,"severity":"error","filePath":"packages/next/src/server/app-render/dynamic-rendering-client.ts","lineNumber":116,"sourceCode":"    case 'prerender-client': {\n      React.use(\n        makeClientHookHangingPromise(\n          workUnitStore.renderSignal,\n          new ClientHookDynamicError(workStore.route, expression)\n        )\n      )\n      break\n    }\n    case 'prerender-legacy': {\n      if (workStore.forceStatic) {\n        return\n      }\n      if (process.env.__NEXT_EXPERIMENTAL_REACT_BROWSER_BAILOUT) {\n        // @ts-expect-error TODO: Update @types/react-dom to include the reason argument.\n        React.use(browser(getUseSearchParamsBailoutReason))\n        return\n      } else {\n        throw new BailoutToCSRError(expression)\n      }\n    }\n    case 'prerender':\n    case 'prerender-runtime':\n      throw new InvariantError(\n        `\\`${expression}\\` was called from a Server Component. Next.js should be preventing ${expression} from being included in server components statically, but did not in this case.`\n      )\n    case 'cache':\n    case 'unstable-cache':\n    case 'private-cache':\n      throw new InvariantError(\n        `\\`${expression}\\` was called inside a cache scope. Next.js should be preventing ${expression} from being included in server components statically, but did not in this case.`\n      )\n    case 'generate-static-params':\n      throw new InvariantError(\n        `\\`${expression}\\` was called in \\`generateStaticParams\\`. Next.js should be preventing ${expression} from being included in server component files statically, but did not in this case.`\n      )\n    case 'request':","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/vercel/next.js/blob/89d017eac43ebf4742ed2b58d3c1373b70283b69/packages/next/src/server/app-render/dynamic-rendering-client.ts#L98-L134","documentation":"This error is thrown when useSearchParams() is called during static prerendering of a Server Component in the App Router. Next.js requires access to search params to be dynamic (request-time); during a static build there is no search params value available, so the renderer throws a BailoutToCSRError with the expression string (e.g. `useSearchParams()`) to signal that this tree must fall back to client-side rendering or be wrapped in a Suspense boundary.","triggerScenarios":"Calling useSearchParams() in a component that is statically prerendered (next build without dynamic = 'force-dynamic') and is NOT wrapped in a <Suspense> boundary; importing a client component using useSearchParams into a statically rendered page layout; using a shared header/navbar reading search params in the root layout during static export.","commonSituations":"Upgrading Next.js versions where previously-tolerated unwrapped useSearchParams became a build error; static export (output: 'export') with a component reading search params; adding a search-param-aware widget to a layout; missing Suspense boundary around the client component.","solutions":["Wrap the component calling useSearchParams() in a <Suspense> boundary (e.g. <Suspense fallback={...}><SearchBar /></Suspense>)","Move useSearchParams() into a dedicated client component ('use client') and isolate it under Suspense","Add export const dynamic = 'force-dynamic' to the route if it genuinely needs request-time rendering","For static export, replace useSearchParams() with reading window.location.search in useEffect, or use next/navigation router handling after mount"],"exampleFix":"// before\nexport default function Page() {\n  return <SearchBar /> // SearchBar calls useSearchParams()\n}\n\n// after\nimport { Suspense } from 'react'\nexport default function Page() {\n  return (\n    <Suspense fallback={<div>Loading...</div>}>\n      <SearchBar />\n    </Suspense>\n  )\n}","handlingStrategy":"validation","validationCode":"import { Suspense } from 'react'\n// Before shipping, verify every useSearchParams() consumer is isolated:\n// grep -rn \"useSearchParams\" app/ components/\n// and statically confirm each usage site is inside a <Suspense> ancestor or force-dynamic route.","typeGuard":"function isStaticRoute(config: { dynamic?: string }): boolean {\n  return config.dynamic !== 'force-dynamic'\n}","tryCatchPattern":"// Not applicable: this is a build-time prerender bailout, not a runtime exception to catch.\n","preventionTips":["Always wrap useSearchParams() consumers in Suspense at the page/layout level","Keep search-param reading in small leaf client components","Set export const dynamic = 'force-dynamic' on routes that depend on query strings","Run next build in CI to catch prerender bailouts before deploy"],"tags":["nextjs","app-router","use-search-params","prerender","static-generation","suspense"],"backgroundTag":"prerender-bailout-to-csr","analyzedSha":"89d017eac43ebf4742ed2b58d3c1373b70283b69","analyzedAt":"2026-08-27T11:26:12.396Z","contentChangedAt":"2026-08-27T11:26:12.396Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}