useSearchParams() should be wrapped in a suspense boundary at page "/search".

Next.js · updated 2026-11-04

Printed by next build while prerendering a static App Router page, followed by "Error occurred prerendering page". Search parameters only exist per request, so a static page that reads them must either render that part on the client inside a Suspense boundary or be rendered per request.

 ⨯ useSearchParams() should be wrapped in a suspense boundary at page "/search". Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout
    at a (/app/.next/server/chunks/514.js:1:10520)
Error occurred prerendering page "/search". Read more: https://nextjs.org/docs/messages/prerender-error
Export encountered an error on /search/page: /search, exiting the build.

Quick fix

Move the code that calls useSearchParams() into its own Client Component and render it inside <Suspense> with a fallback. The rest of the page stays static. If the whole page depends on the query string, make it dynamic instead: read the searchParams prop in the page (a Server Component) or call await connection() from next/server.

  1. Find the component named in the stack that calls useSearchParams() (often a filter bar, search box or pagination).
  2. Keep it a Client Component ('use client') and render it as <Suspense fallback={...}><Filters /></Suspense> in the page.
  3. If the page should be rendered per request, use the searchParams prop of the page instead of the hook, or await connection() in the page.
  4. Run next build locally to confirm the page prerenders (or shows as dynamic) instead of failing.
typescript
// app/search/page.tsx (Server Component)
import { Suspense } from 'react';
import { Filters } from './filters'; // 'use client' file that calls useSearchParams()

export default function SearchPage() {
  return (
    <main>
      <h1>Search</h1>
      <Suspense fallback={<p>Loading filters…</p>}>
        <Filters />
      </Suspense>
    </main>
  );
}

Why it happens

A client hook on a static page

The page has no dynamic data, so Next.js prerenders it at build time; useSearchParams() has no value there, and without Suspense the whole page would fall back to client rendering.

Suspense too high or missing in a shared component

A header or layout component reads the query string, so every page that uses it fails the build until the boundary sits around that component.

Upgrading to Next.js 15

This has failed the build since Next.js 14.1. On 14 it could be switched off with experimental.missingSuspenseWithCSRBailout; Next.js 15 removed that flag, so projects that relied on it fail after the upgrade.

Other fixes

  • With cacheComponents enabled the same mistake reports a different message that links to /docs/messages/blocking-prerender-client-hook; the fix is the same Suspense boundary.
  • export const dynamic = 'force-dynamic' also makes the build pass, but renders the whole page on every request.

Same error, other wording

  • Missing Suspense boundary with useSearchParams
  • Error occurred prerendering page "/". Read more: https://nextjs.org/docs/messages/prerender-error
  • useSearchParams() should be wrapped in a suspense boundary at page "/404".

Let your coding agent catch the next one

Runheed records this error in production with the stack trace, the breadcrumbs before it and the agent session that shipped the code, and serves it to Claude Code, Cursor or any MCP client. With it connected, you can ask:

> Find which component calls useSearchParams() on the page that fails to build, wrap it in a Suspense boundary with a fallback (or read the searchParams prop in the page), and confirm next build passes.

Plans from $29/moSee what your agent readsSee the setupCancel any time from the billing portal

Related errors

More in React and Next.js rendering

References: Next.js docs: Missing Suspense boundary with useSearchParams, Next.js docs: useSearchParams