Question presented to candidate: "Why does the error boundary in a React Server Components app have to be a Client Component?"
What a strong answer should cover:
- An Error Boundary needs
getDerivedStateFromError,componentDidCatchand state to hold the error. A Server Component has no state, no lifecycle and renders once — so it cannot be one. - Boundaries therefore live on the client, marked
"use client", and they can still wrap Server Components rendered as their children, because composition crosses the boundary even though code does not. - When a Server Component throws on the server, the framework serialises the failure into the stream and the nearest client boundary renders its fallback.
- In production the message is redacted. You get a digest — a hash to correlate with your server logs — not the original message, because a server error can contain a query, a path, or a secret.
- That is a genuine debugging difference: server errors are found in your server logs, not in the browser console.
- Recovery is different too. A client boundary cannot re-run a Server Component's render on its own — retrying needs a new request to the server, which is what a framework's
resetdoes. - In Next.js the App Router convention is an
error.tsxfile, which must carry"use client"for exactly this reason. - Server-side errors that never reach a boundary — a route handler, a failed Server Action — need server-level observability instead.
Clarifying questions expected:
- "Did the error happen during the server render, or after hydration on the client?" — different diagnosis entirely.
- "Do we have server-side error reporting wired up?"
Code / implementation expected: Optional. Pointing out the "use client" on the boundary is the substance.