Skip to content

Custom 404 responses

Replace Flare's plain-text 404 with your own response by registering a low-specificity wildcard catch-all.

AI generated, pending review Updated 10 days ago · Flare 0.3

When no pipeline matches the request path, Flare returns a framework 404 with the plain-text body Not Found. You want your own response instead, maybe a JSON envelope your clients already parse. Register a wildcard catch-all route at low specificity so a pipeline always matches and your handler returns the response you choose.

That default 404 does not route through host.http.error(). Flare returns it before any pipeline runs, so an error handler never sees an unmatched path.

  1. Register a wildcard route with host.http.get("/*path", handler).
  2. Return your own FlareResponse from that handler.
  3. Repeat for each method you want covered.
import { FlareHost, FlareResponse } from "@flare-ts/core";
import { node } from "@flare-ts/core/node";
const host = new FlareHost(node);
host.http.get("/health", () => new FlareResponse(200, { ok: true }));
host.http.get("/*path", (ctx) => {
return new FlareResponse(404, `No route for ${ctx.req.path}`);
});
const app = host.build();
app.run();

A GET /health request still hits the real handler. A GET /anything-else falls through to the catch-all. The wildcard segment scores 0 for specificity, while literals score 2 and parameters score 1, so every real route outranks the catch-all.

import { FlareHost, FlareResponse } from "@flare-ts/core";
import { node } from "@flare-ts/core/node";
const host = new FlareHost(node);
host.http.get("/*path", (ctx) => {
return new FlareResponse(404, {
error: "not_found",
path: ctx.req.path,
});
});
const app = host.build();
app.run();
import { FlareHost, FlareResponse } from "@flare-ts/core";
import type { HttpRouteHandler } from "@flare-ts/core";
import { node } from "@flare-ts/core/node";
const host = new FlareHost(node);
const notFound: HttpRouteHandler = (ctx) =>
new FlareResponse(404, { error: "not_found", path: ctx.req.path });
host.http.get("/*path", notFound);
host.http.post("/*path", notFound);
host.http.put("/*path", notFound);
host.http.patch("/*path", notFound);
host.http.delete("/*path", notFound);
const app = host.build();
app.run();
  • The catch-all changes 404 behavior only. A path that matches a real route but uses an unregistered method still returns 405 with an Allow header.
  • There’s no host.http.all helper. Register each method explicitly.
  • With /*path, read the unmatched tail from ctx.req.rawRouteParams["path"].
  • The catch-all does not cover the root path. /*path needs at least one segment, so a request to / still returns the framework 404 unless you also register a route for /.