Errors & not-found
Two boundary files handle failures. Neither has a URL.
_404.tsxrenders when no route matches a URL under its directory._error.tsxrenders when a handler or middleware throws. Resolution climbs to the nearest boundary.
notFound
throw notFound() renders the 404 page.
import { notFound } from 'camelon';
import type { GetFunction } from 'camelon';
export const get: GetFunction = () => {
throw notFound('No such page');
};redirect
throw redirect(url, status?) sends a redirect. The default status is 302. A Datastar request gets a client-side navigation instead, so in-page actions move the user without a reload.
import { redirect } from 'camelon';
import type { GetFunction } from 'camelon';
export const get: GetFunction = () => {
throw redirect('/hello');
};HttpError
throw new HttpError(status, message) for any other status.
import { HttpError } from 'camelon';
import type { GetFunction } from 'camelon';
export const get: GetFunction = () => {
throw new HttpError(403, 'Forbidden');
};Per-route error boundary
A page route can export error to render its own failure UI:
export const error: ErrorFunction = (err, input, request, source, errorId) => (
<div class="error">
<h1>Something broke</h1>
<p safe>{err.message}</p>
<code safe>{errorId}</code>
</div>
);
This route throws, and its own error boundary renders in place — no crash, no blank page:
import { HttpError } from 'camelon';
import type { GetFunction, ErrorFunction } from 'camelon';
export const get: GetFunction = () => {
throw new HttpError(418, "I'm a teapot");
};
export const error: ErrorFunction = (e) => (
<div class="d-card">
<strong>Caught by the route's boundary</strong>
<p>
{e.name}: {e.message}
</p>
</div>
);
export default function Boundary() {
return <div class="d-card">this never renders — the get handler throws first</div>;
}errorId is the request correlation id. Print it so a user can quote it and you can find it in the logs.