Loading...
Loading...
Ossido catches errors from your Rust handlers so a single failure never takes down
the server, surfaces them clearly in development, and gives you two places to shape
what happens next: an error.tsx route for the page users see, and
set_error_handler for server-side reporting and custom responses.
Handlers don't need explicit error plumbing. If one panics, Ossido catches it (via
catch_handler) and surfaces it as a rich [BE] ERROR log plus a client error
overlay in development, instead of crashing the server. The ServerError and
ErrorSource types model the failure and where it came from.
For expected outcomes - a missing record, an upstream request that failed -
prefer returning a Response with the appropriate status over panicking:
Reserve panics for genuinely unexpected, unrecoverable situations - Ossido will turn those into the error page for you.
error.tsxOssido ships a default error page, but you can replace it with your own React
component by adding an error.tsx route (see
File System Routing for where it sits among the reserved
files). It's a client-rendered error boundary: Ossido renders it in place of
the subtree whenever a descendant route throws during render, a data resource
rejects, or the route's Rust handler fails.
It receives OssidoErrorProps:
error - the value that was thrown, so you can branch on it (an Error with
name/message, or whatever a resource rejected with).reset - a callback that re-renders the boundary's children. Wire it to a
"Try again" button so a transient failure (say a flaky request) can recover in
place, without a full reload.An error.tsx catches its own folder and everything below it. Put one at
src/routes/error.tsx to catch the whole app, or drop another inside a subtree
(e.g. src/routes/dashboard/error.tsx) to contain failures there and keep the rest
of the page interactive. The nearest boundary above the throwing route wins, so a
nested boundary handles things locally while the root one is the final safety net.
In development Ossido also shows a detailed error overlay (message and stack) over
the top, so you can debug without your error.tsx hiding the cause. In production
only your error.tsx (or the default page) is shown - so don't render
error.message to users unless you're certain it's safe, since it can leak
internals. Keep the fallback to recovery affordances (retry, a link home) and do
the reporting server-side with set_error_handler, below.
set_error_handlerTo do something with every caught error - report it to Sentry (or anything
similar), and optionally replace the default 500 with your own response -
register a handler once from src/app.rs's main(), before the server starts:
The handler is async, so you can .await a report before responding. It runs
for both page and API handler errors, and is given an ErrorContext:
error - the ServerError (name, message, stack, source).request - the Request that failed (read params, location(), headers).mode - whether the server is in development or production.error_id - a unique id for this occurrence, so a report (e.g. a Sentry
event) and a user-facing page can be correlated.Returning Some(response) sends that response in place of the default; returning
None falls back to Ossido's standard error page (the dev overlay, or a
detail-free 500 in production). Either way the error is still logged to the
server console. Only the first registration takes effect, so register it once.
set_error_handler takes any closure (or function) matching this shape:
In plain terms, the handler:
Fn (not FnOnce) - it's stored and called on every error, so it may
be invoked many times and can't consume captured values.ErrorContext by value - it owns its data, so you can hold it
across an .await.Future - this is what makes the handler async - resolving to
Option<Response>: Some overrides the response, None keeps the default.Send + Sync + 'static, and its future is Send + 'static, because
it lives for the whole process and runs inside the async server. In practice
this means captured state must be thread-safe (e.g. an Arc<Client>).The Response is a re-exported ossido::axum::response::Response, so build it with
the axum types (StatusCode, Json, tuples, ...) as in the example above.
Back to Page & Layout Handlers · File System Routing