Errors & Not Found
Handle 404 Not Found, 500 Server Errors, and route exceptions with localized layouts, action buttons, and loader boundaries.
In TanStack Start, error handling and missing routes are configured through route boundaries rather than static files. VitNode provides built-in, localized error layouts (NotFound, Error500Page, and ErrorActions) mounted directly inside your application shell—keeping navigation, headers, and themes intact when errors occur.
404 Not Found
Throwing 404 in loaders
When a requested resource (such as a note slug or user ID) is not found in the database, throw notFound() from @tanstack/react-router inside load:
import { notFound } from '@tanstack/react-router'
import { definePluginRoute } from '@vitnode/core/routing'
export const route = definePluginRoute({
load: async ({ params }) => {
const note = await fetchNote(params.slug)
if (!note) {
throw notFound()
}
return note
},
})When thrown, TanStack Router catches the signal and halts page execution, rendering the nearest notFoundComponent.
Unmatched URLs keep the main shell
When a visitor navigates to a non-existent URL, the main shell (_main.tsx) is
still matched, so the route is caught inside it.
This ensures visitors never hit a blank, unstyled screen: they retain the main site header, navigation bar, and theme switcher, while search crawlers receive a real HTTP 404 status code:
const routeTree = withVitNodeRoutes(
fileRouteTree,
pluginRouteSpecs(pluginRouteSources),
{
mountUnder: {
admin: adminShellRoute,
blank: fileRouteTree,
main: mainShellRoute,
},
},
)500 Server & runtime errors
When an unhandled exception or database failure occurs during SSR or client navigation, the router activates its errorComponent.
VitNode configures the global error boundary in apps/web/src/router.tsx using Error500Page:
import { createRouter as createTanStackRouter } from '@tanstack/react-router'
import {
Error500Page,
ErrorActions,
NotFound,
} from '@vitnode/core/tanstack/layout'
export function getRouter() {
return createTanStackRouter({
routeTree,
defaultNotFoundComponent: () => <NotFound actions={<ErrorActions />} />,
defaultErrorComponent: () => <Error500Page actions={<ErrorActions />} />,
})
}Error500Page automatically renders localized strings from core.global.errors.500, keeping the error message friendly and clear while preserving layout structure.
Error action buttons
The <ErrorActions /> component renders two primary recovery buttons:
- Go Back (
router.history.back()) — Takes the user to their previously viewed screen. - Back to Home (
/) — Returns to the application homepage using locale-aware navigation.
You can also pass custom action elements into the actions prop of NotFound or Error500Page:
import { ErrorActions, NotFound } from '@vitnode/core/tanstack/layout'
export const Route = createRootRouteWithContext<RootRouterContext>()({
notFoundComponent: () => <NotFound actions={<ErrorActions />} />,
component: RootComponent,
})Standard error codes
VitNode provides ErrorContent to render standardized error presentations across public and administrative pages:
| Status code | Name | Common cause | Handled by |
|---|---|---|---|
400 | Bad Request | Malformed request parameters or invalid form payloads | ErrorContent |
403 | Forbidden | Insufficient permissions or unauthorized staff action | Staff auth guards |
404 | Not Found | Route does not exist or loader threw notFound() | NotFound |
409 | Conflict | Resource already exists or version mismatch | API mutation handlers |
429 | Too Many Requests | Rate limits exceeded on public or API endpoints | Rate limiter middleware |
500 | Internal Server Error | Uncaught server exception or database connectivity issue | Error500Page |
Centralized error boundaries
Keep root error fallbacks in your host application (apps/web). Individual
plugins should throw notFound() or errors from their loaders and let the
centralized, localized layouts handle presentation.