T
TanStack2w ago
foreign-sapphire

Best practice for error handling

I am thrilled that tanstack start offers a bunch of options for error handling and I need to get my head around this. I wonder what is the best practice for this scenario: 1. Option: Error handling in server function and providing a graceful fallback with empty data result
# eventsService.tsx
export const getEvents = createServerFn()
.middleware([authMiddleware])
.handler(async ({ context }) => {
try {
# DB CALL
return events;
} catch (error) {
prodError("SERVER" ...);
return { rows: [], total: 0 };
}
});


# events.index.tsx
export const Route = createFileRoute("/(protected)/admin/events/")({
loader: async () => eventsService.getEvents(),
component: RouteComponent,
});

function RouteComponent() {
# ...
# eventsService.tsx
export const getEvents = createServerFn()
.middleware([authMiddleware])
.handler(async ({ context }) => {
try {
# DB CALL
return events;
} catch (error) {
prodError("SERVER" ...);
return { rows: [], total: 0 };
}
});


# events.index.tsx
export const Route = createFileRoute("/(protected)/admin/events/")({
loader: async () => eventsService.getEvents(),
component: RouteComponent,
});

function RouteComponent() {
# ...
2. Option: Error handling in the route with onError
# eventsService.tsx
export const getEvents = createServerFn({ method: "GET" })
.middleware([authMiddleware])
.handler(async ({ context }) => {
# DB CALL
return events;
});


# events.index.tsx
export const Route = createFileRoute("/(protected)/admin/events/")({
loader: async () => eventsService.getEvents(),
component: RouteComponent,
onError: ({ error }) => {
// Log the error for debugging/monitoring
console.error("CLIENT ❌ events.tsx Failed to load events", error);
}
e
});

export const Route = createFileRoute("/(protected)/admin/events/")({
loader: async () => eventsService.getEvents(),
component: RouteComponent,
onError: ({ error }) => {
// prodError also sends to sentry
prodError("CLIENT", "events.tsx", "Failed to load events");
},
errorComponent: ({ error }) => {
return (<div className="text-center py-8 text-muted-foreground">
<p> {error.message}</p>

</div>
)
}
});

function RouteComponent() {
# ....
# eventsService.tsx
export const getEvents = createServerFn({ method: "GET" })
.middleware([authMiddleware])
.handler(async ({ context }) => {
# DB CALL
return events;
});


# events.index.tsx
export const Route = createFileRoute("/(protected)/admin/events/")({
loader: async () => eventsService.getEvents(),
component: RouteComponent,
onError: ({ error }) => {
// Log the error for debugging/monitoring
console.error("CLIENT ❌ events.tsx Failed to load events", error);
}
e
});

export const Route = createFileRoute("/(protected)/admin/events/")({
loader: async () => eventsService.getEvents(),
component: RouteComponent,
onError: ({ error }) => {
// prodError also sends to sentry
prodError("CLIENT", "events.tsx", "Failed to load events");
},
errorComponent: ({ error }) => {
return (<div className="text-center py-8 text-muted-foreground">
<p> {error.message}</p>

</div>
)
}
});

function RouteComponent() {
# ....
2 Replies
generous-apricot
generous-apricot3d ago
I just noticed that the custom error message doesn’t make it through when throwing inside a server function. I’m wondering if the same thing happens to you, or if you can actually see the error message in the browser when it comes from a server function? https://discord.com/channels/719702312431386674/1442369658702397581
rising-crimson
rising-crimson3d ago
option 1 gives you a lot more flexibility in your stack IMO, as you could have situations where a full component on error might not be what you want. you can also still throw an error from server side and it will propagate back down

Did you find this page helpful?