SSR framework for Svelte 5 + Bun with islands-based selective hydration
On this page
Error handling
Mochi renders an HTML error page for any uncaught error that escapes a page render: top-level SSR throws, error(status, ...) from serverProps or actions, malformed form bodies, unknown form actions, and unmatched routes. API routes return a JSON envelope instead. Island-level boundaries are scoped to hydratable islands — see Error boundaries.
errorPage is omitted. The stack trace renders only under development: true.Configure the page with errorPage on Mochi.serve(). Omit it to use the built-in component.
// file: src/index.ts
import { Mochi } from 'mochi-framework';
await Mochi.serve({
errorPage: './src/Error.svelte',
routes: {
'/': Mochi.page('./src/Home.svelte'),
},
});errorPage
The component receives one error prop typed by MochiErrorProps.
<!-- file: src/Error.svelte -->
<script lang="ts">
import type { MochiErrorProps } from 'mochi-framework';
let { error }: MochiErrorProps = $props();
</script>
<h1>{error.status}</h1>
<p>{error.message}</p>
{#if error.stack}<pre>{error.stack}</pre>{/if}| Field | Description |
|---|---|
status | HTTP status — 404, 500, or whatever was passed to error() |
message | Human-readable message, safe to render |
stack | Stack trace, populated only when development: true, else absent |
Default behavior without errorPage:
- Unmatched routes →
404 Not Found. - Uncaught throws in
serverProps, page render, or an action handler →500 Internal Server Error. error(status, message?)thrown from any of these → that exactstatus, with the message defaulting to the canonical status text when omitted.
Request context in the error page
Since: 0.10.0 (not released yet): Before 0.10.0, unmatched-route 404s rendered the error page without a request context.
getRequestContext() works inside the error component — url, cookies, and locals behave as on any page, so a shared nav can read the current path. On unmatched-route 404s the context is minimal: params is empty because no route matched.
<!-- file: src/Error.svelte -->
<script lang="ts">
import { getRequestContext, type MochiErrorProps } from 'mochi-framework';
let { error }: MochiErrorProps = $props();
const { url } = getRequestContext();
</script>
<h1>{error.status}</h1><p>No page at {url.pathname}</p>handleError
Fires whenever the error page is about to render. Use it to log, forward to error tracking, or sanitize the message the user sees.
// file: src/index.ts
import type { HandleError } from 'mochi-framework';
const handleError: HandleError = ({ error, event, status, message }) => {
if (error) tracker.capture(error, { path: event.url.pathname });
if (status === 404) return Response.redirect(new URL('/', event.url), 302);
if (status >= 500) return { status, message: 'Something went wrong.' };
};
await Mochi.serve({
errorPage: './src/Error.svelte',
handleError,
routes: {
'/': Mochi.page('./src/Home.svelte'),
},
});Return one of:
{ status, message }— override either field passed to the error component.- a
Response— short-circuit rendering (useful for redirects). void— keep the defaults.
error is null when the condition did not come from a throw (unmatched routes, unknown form actions). Inspect it before forwarding so benign 4xx cases do not page on-call.
If the hook itself throws, Mochi logs the secondary error and renders the error page with the original status and message.
API error envelope
Mochi.api routes return { "error": { "message", "status" } } with the matching status code. Use MochiHttpError (typed throw via error()) or apiError() (typed return) to produce the envelope. See API routes.
Fallback behavior
If your errorPage throws during render, Mochi returns a plain-text response mentioning both the original error and the secondary render failure. The error page cannot crash the server.
See it in action
Live demos showing key concepts from this page