DocsOperations
Error handling
Return expected failures explicitly, render page errors at the nearest boundary, and keep internal diagnostics out of production responses.
Choose what the client may read
pub async fn page() -> rahti::Result<Html> {
let order = find_order().await?
.ok_or_else(|| rahti::Error::new(
StatusCode::NOT_FOUND,
"Order not found",
))?;
Ok(html! { <h1>@{order.number}</h1> })
}| Constructor | Production exposure |
|---|---|
| Error::new(4xx, message) | The client receives the message. |
| Error::new(5xx, message) | The server records it; the client receives generic text. |
| Error::internal(message) | Private diagnostic with HTTP 500. |
| Error::public(status, message) | Explicitly public text at any status. |
| with_public_message | A private diagnostic plus separate client-safe text. |
An ordinary error crossing ? also becomes a private internal failure. Never copy Error::message() into a response; it is the server diagnostic.
Nested page boundaries
pub fn error(error: rahti::ErrorInfo) -> Html {
let reference = error.request_id()
.map(|id| format!("Reference: {id}"));
html! {
<section>
<h1>@{error.reason()}</h1>
<p>@{error.message()}</p>
<small>@{reference}</small>
</section>
}
}The nearest ancestor boundary replaces the failed subtree. Layouts below it are skipped and layouts above it remain. ErrorInfo contains the safe status, reason, message, and optional request-id reference. RPC errors never render a page boundary.
API and RPC shapes
An unhandled page or route.rs failure uses application/problem+json. RPCs preserve the PulsePoint JSON wire with error and optional requestId. Validation stays HTTP 422 with field errors; malformed arguments stay HTTP 400.
