T
TanStack4d ago
stormy-gold

How to handle notFound errors based on route param validation?

I have a lot of routes like /posts/$postId where I essentially just call a server function to get the relevant post:
// route
export const Route = createFileRoute("/posts/$postId")({
component: RouteComponent,
loader: async ({ context: { queryClient }, params: { postId } }) => {
// should validate and throw notFound before get here?
await queryClient.ensureQueryData(postQueryOptions(postId));
},
});
// route
export const Route = createFileRoute("/posts/$postId")({
component: RouteComponent,
loader: async ({ context: { queryClient }, params: { postId } }) => {
// should validate and throw notFound before get here?
await queryClient.ensureQueryData(postQueryOptions(postId));
},
});
// serverFn
export const getPost = createServerFn({ method: "GET" })
.validator(z.object({ id: z.uuid() }))
.handler(async ({ data: { id } }) => {
const post = await db.query.posts.findFirst({
where: { id }
...
})

if (!post) throw notFound();
return post
});
// serverFn
export const getPost = createServerFn({ method: "GET" })
.validator(z.object({ id: z.uuid() }))
.handler(async ({ data: { id } }) => {
const post = await db.query.posts.findFirst({
where: { id }
...
})

if (!post) throw notFound();
return post
});
With this setup zod throws a validation error when the postId param is not a valid UUID - which I want because then it doesn't actually have to unnecessarily query the database. However ideally I would want to throw an error using notFound() instead in these cases so the correct not found error component is shown rather than the generic one. I assume I'm missing some logic about how to handle this in router and it shouldn't be getting to the point that the serverFn is actually called but I've struggled to find anything relevant in the docs - hoping I'm just being dumb?
5 Replies
stormy-gold
stormy-goldOP4d ago
also concerned I'm not actually handling notFound errors thrown in server functions correctly, because if I remove the preloading of the query from the loader I get weird behaviour based on if its SSR or not. On page refresh I get this in console:
Error in renderToPipeableStream: { isNotFound: true } { componentStack: [Getter] }
Error in renderToPipeableStream: { isNotFound: true } { componentStack: [Getter] }
and the route layout is no longer rendered, just the full screen notFound component. where as on navigation I just get a white screen
firm-tan
firm-tan21h ago
so you want to convert the error from a zod error to notFound? should be doable via a function middleware however, why dont you validate the params in the route using params.parse BEFORE the loader would be called? probably best if you create a github issue including a complete minimal example repository for this one
stormy-gold
stormy-goldOP21h ago
Yeah catching it before rather than converting sounds like the best approach, guess I was overthinking it looking for something like validateSearch but for params rather than doing it in the loader
firm-tan
firm-tan21h ago
params.parse is like validateSearch
stormy-gold
stormy-goldOP21h ago
oh yeah I'm blind, will give that a go haha - thanks for the help

Did you find this page helpful?