A nested segment's server-side data fetch throws while the route is being served — what does the user end up seeing?
answer
- it is caught, not dropped
- nearest declared failure state upwards
- blast radius follows boundary placement
- missing record is not a server error
basics
~20 sThe framework catches the throw and renders the nearest declared failure state in the matched chain, leaving the segments above it intact. How much of the page that replaces depends on where the nearest boundary sits.
solid answer
~50 sA throw inside a route's data function does not produce a blank page. The framework unwinds to the nearest failure boundary declared in the matched segment chain and renders that instead of the failing segment's UI, leaving outer layouts — navigation, shell, anything already resolved — in place. The practical consequence is that boundary placement is a design decision: a boundary only at the root turns any read failure into a whole-page error, while one per major region keeps the rest of the route usable. Distinguish the two kinds of failure, too. An expected outcome such as *this record does not exist* or *you may not see this* should be signalled deliberately, so the response carries a matching status and its own state; an unexpected error should be logged server-side with detail and shown to the user as a generic message, never as a raw stack or database text.
go deeper
Remember that the framework catches the throw and renders a declared failure state rather than nothing, and that outer layouts above the failing segment stay on screen.
Explain the upward search for the nearest boundary, and separate expected outcomes with their own status from unexpected errors that log detail server-side and show a generic message.
Demonstrate operating judgment: timeouts per read, correlation identifiers surfaced to users, tested failure paths, and boundary placement chosen so a secondary read cannot kill a route.
Set the policy: which failures are allowed to take a route down, what a failure state must never reveal, and how status codes stay consistent for crawlers, caches and monitoring across the whole site.
## What the framework does with a throw When a matched segment's data function throws, the framework stops rendering that segment's subtree and looks **upwards through the matched chain** for the nearest declared failure state. That state is rendered in place of the failing segment. Everything above it that already resolved — outer layouts, navigation, sibling regions — survives. The result is a page that is partly broken rather than entirely gone. This is the same containment idea as an error boundary in a component tree, but it applies at the *route* level and it applies to data that is fetched **before** any of the UI has rendered. That distinction is what an interviewer is usually probing: the failure happens in the data phase, not during rendering, and the router already knows which segment owned the failing read. ## Boundary placement is the design decision | Where failure states are declared | A leaf read fails | Cost | |---|---|---| | Only at the root | The whole page is replaced by an error screen | Simple, but one flaky read kills the route | | At each major region | The region shows an error; the rest stays usable | More states to design and maintain | | At every segment | Failures are pinpointed | A patchwork of error states, easy to lose the overall message | The useful test is a question about the product, not the code: *if this read fails, is the rest of this page still worth showing?* If yes, there should be a boundary between it and the rest. If no — the route is meaningless without that data — let it bubble to the level where the page as a whole reports failure. ## Expected outcomes versus unexpected errors Two different things get called "an error" and they deserve different handling. 1. **Expected outcomes.** The record does not exist; the caller is not permitted; the input was invalid. These are normal branches of a correct program. Signal them deliberately so the framework can render the matching state and the response carries the right status — a not-found status for a missing record, an unauthorised or forbidden status for a permission failure. Crawlers, link checkers, monitoring and shared caches all read that status; returning a success status with an error-looking page teaches every one of them the wrong thing. 2. **Unexpected errors.** The data source timed out, a dependency threw, a bug fired. These are a server-error status. Log the detail — message, stack, correlation identifier, the route and parameters — on the server, and show the user a generic message plus an identifier they can quote. Raw exception text in the browser leaks schema, file paths and library versions. ## The document request and the client navigation differ - On a **document request** the failure state is part of the HTML and the response carries the status code that matches it. - On a **client-side navigation** there is no new document, so the status line is not what the user's page reacts to. The failure must be carried in the navigation payload so the already-running client can render the same boundary. The user-visible result should be identical; the transport is not. A related subtlety: if the framework streams the response, some markup may already have been flushed before the read fails, which constrains what can still be changed about the response. How a slow or failing part is handed off mid-response is its own mechanism; the point to retain here is that once bytes are out, the status line is not one of them. ## Operational habits worth stating - **Timeouts and budgets.** A read with no timeout turns a slow dependency into a hung route. Bound it and fail into the boundary deliberately. - **Degrade where it is honest.** For genuinely secondary data, an empty or partial state can beat an error screen — but only when the page remains truthful without it. Never hide a missing primary record behind an empty list. - **Correlate.** Emit an identifier with the logged error and show it in the failure state; that single habit is what turns "the page broke" into a lookup. - **Test the path.** Failure states rot because nobody exercises them. Force a read to fail in a test and assert the boundary, the status and the absence of internal detail. ## The crisp answer Nearest declared failure state, outer layouts preserved, boundary placement decides the blast radius; expected outcomes get their own state and a matching status, unexpected ones get a generic message plus a server-side log with detail.
- Why does returning an empty result instead of a not-found outcome cause trouble?Because the response then claims success. Crawlers index the page, monitoring sees no error, shared caches store it, and the user is told a record exists but is empty rather than that the URL is wrong. Signal the missing record explicitly so the status and the rendered state agree.
- What should a user see when an unexpected read failure happens in production?A generic failure state with a correlation identifier, and nothing internal — no stack, no query text, no dependency names. The detail belongs in the server log keyed by that identifier, where support can find it without exposing schema or infrastructure to whoever triggered the error.
- How do you decide whether a failed read should take down the whole route?Ask whether the page is still truthful and useful without that data. Primary content — the record the URL names — should fail the route. Secondary panels should fail inside their own boundary so the rest stays usable. Encode that decision as where you declare the failure state.
saying these in an interview costs you the question
- Expects a blank page when a route data fetch throws
- Returns a success status alongside an error page
- Shows raw exception text to the user in production
- Treats a missing record as a server error
- Declares one failure state at the root and calls it handled
- Leaves reads without a timeout and calls a hung route a network issue