Diagnostics
LUM5009: Boundary still pending when streamTimeout expired
A <Suspense> boundary was still waiting for data when lumiose({ streamTimeout }) expired.
Severity: error · Category: routing and server (5xxx)
Reported by: the server runtime, to the <ErrorBoundary> around the waiting component (or to
the boundary itself), to onRequestError with phase "stream", and to the server log.
#What it means
A page render waits for its pending <Suspense> boundaries for streamTimeout, 30 seconds by
default. When it expires, every async component still waiting fails with this error: the nearest
<ErrorBoundary> around it renders its fallback into the stream. A boundary with no
<ErrorBoundary> inside keeps its <Suspense> fallback. Then the response ends, so a data source
that never answers cannot hold the connection open. In production the <ErrorBoundary> fallback
receives a generic error with a digest, as for any error (the log has the original).
A response that does not stream (response().setStreaming(false)) waits for the same timeout; there
a boundary with no <ErrorBoundary> fails the page, as any error inside it would.
#Example
export default function Dashboard() {
return (
<Suspense fallback={<p>Loading…</p>}>
<ErrorBoundary fallback={<p>The report is taking too long. Try again later.</p>}>
<Report />
</ErrorBoundary>
</Suspense>
);
}
async function Report() {
const report = await fetchJSON<Report>("/api/report"); // the service never answers
return <ReportTable report={report} />;
}#How to fix it
Find the data source that did not answer in time (onRequestError receives the route). Give it its
own timeout or cache, render an <ErrorBoundary> around the component so readers see a useful
fallback, or raise the limit with lumiose({ streamTimeout: "60s" }). streamTimeout: false waits
as long as the client stays connected. Prerendering ignores the timeout.