T
TanStack•3mo ago
rival-black

Getting "Function is not serializable" errors when passing functions into the router context

As the title says, I am trying to pass some functions (in this case, my API call client) to my router context to make data fetching easier. This is suggested as a best practice in the Tanstack Router docs as well. However, I keep getting errors saying "Function is not serializable" and my builds are now failing. This issue seemingly has occurred overnight in our application. Using Tanstack Router 1.132.6 and Node v22.19.0
Router Context | TanStack Router React Docs
TanStack Router's router context is a very powerful tool that can be used for dependency injection among many other things. Aptly named, the router context is passed through the router and down throug...
24 Replies
sensitive-blue
sensitive-blue•3mo ago
i dont see anywhere in the docs (even in your link) where it says that passing functions to context is ok anyway, you can't, because, as the error says, it's not serializable and because it's not serializable, it cannot be transmitted via http nor can it be injected into the dom
rival-black
rival-blackOP•3mo ago
No description
rival-black
rival-blackOP•3mo ago
Never said I wanted to transmit a function over HTTP. Just want to reuse something akin to a custom fetch across parent and child routes
sensitive-blue
sensitive-blue•3mo ago
got it (your link's anchor didn't point to this section) can you show your function as well as your router.tsx files ?
rival-black
rival-blackOP•3mo ago
Snippet
export const Route = createRootRoute({
component: RouteComponent,
beforeLoad: async () => {
const api = apiClient({});
return {
api,
};
},
});

function RouteComponent() {
return (
<QueryClientProvider client={tanstackQueryClient}>
<Box style={{ height: '100dvh', display: 'flex', flexDirection: 'column' }}>
<Outlet />
</Box>
<TanStackRouterDevtools />
</QueryClientProvider>
);
}

const apiClient = ({ organizationId, sectionId }: ApiClientParams) => {
return hc<HonoApp>(import.meta.env.VITE_REST_API, {
init: {
credentials: 'include',
headers: {
[OrganizationIdHeader]: organizationId!,
[SectionIdHeader]: sectionId!,
},
},
fetch(input, requestInit, _Env, _executionCtx) {
if (requestInit && ['POST', 'PUT'].includes(requestInit.method ?? '') && requestInit.body) {
requestInit.headers = {
...requestInit.headers,
'Content-Type': 'application/json',
};
}
return fetch(input, requestInit);
},
}).v1;
};
export const Route = createRootRoute({
component: RouteComponent,
beforeLoad: async () => {
const api = apiClient({});
return {
api,
};
},
});

function RouteComponent() {
return (
<QueryClientProvider client={tanstackQueryClient}>
<Box style={{ height: '100dvh', display: 'flex', flexDirection: 'column' }}>
<Outlet />
</Box>
<TanStackRouterDevtools />
</QueryClientProvider>
);
}

const apiClient = ({ organizationId, sectionId }: ApiClientParams) => {
return hc<HonoApp>(import.meta.env.VITE_REST_API, {
init: {
credentials: 'include',
headers: {
[OrganizationIdHeader]: organizationId!,
[SectionIdHeader]: sectionId!,
},
},
fetch(input, requestInit, _Env, _executionCtx) {
if (requestInit && ['POST', 'PUT'].includes(requestInit.method ?? '') && requestInit.body) {
requestInit.headers = {
...requestInit.headers,
'Content-Type': 'application/json',
};
}
return fetch(input, requestInit);
},
}).v1;
};
(Slightly simplified and some things redacted) This is in the root route but same thing occurs in any route
sensitive-blue
sensitive-blue•3mo ago
ah well actually this is as i said this is not equivalent to the screenshot you sent you CAN inject functions into the global context from getRouter in router.tsx but you cannot do that from beforeLoad at this point, everything must be serializable
rival-black
rival-blackOP•3mo ago
This worked completely as expected as of 24 hours ago for the past 6 months But within the last 24 hours, type checking break everywhere
sensitive-blue
sensitive-blue•3mo ago
well, the last version, if you're not aware, is a RC for start v1 so it introduced a lot of breaking changes anyway, are you able to instanciate your apiClient in router.tsx instead ? if so, then that should work
rival-black
rival-blackOP•3mo ago
Also one more important distinction. Types break, code continues to work just fine
sensitive-blue
sensitive-blue•3mo ago
there might be some type issue then, you're probably right
rival-black
rival-blackOP•3mo ago
are you able to instanciate your apiClient in router.tsx instead
i can, but different routes and their parents may need the apiClient instantiated with different params, which is why injecting it into the parent and having all the children just pull api from the context makes the code very clean, readable, and easy to use
sensitive-blue
sensitive-blue•3mo ago
i see
rival-black
rival-blackOP•3mo ago
there might be some type issue then, you're probably right
correct
sensitive-blue
sensitive-blue•3mo ago
file an issue on gh
correct-apricot
correct-apricot•3mo ago
I'm getting the same type error and it seems to be due to missing ssr: false option in the createFileRoute configuration It seems that SSR is true by default now and the types are warning us for non-serializeable things
rival-black
rival-blackOP•3mo ago
Is there a way to set ssr to false globally for every route? I'm surprised this big of a breaking change went out
sensitive-blue
sensitive-blue•3mo ago
but this doesnt explain why it does work at runtime though @munch319 https://discord.com/channels/719702312431386674/1420150535629180988 found this not a type issue (dont know why it works though)
rival-black
rival-blackOP•3mo ago
@teemu Adding ssr: false to every single route fixes it, just need a way to disable it globally. The ssr param on the router only allows you to pass in a nonce
correct-apricot
correct-apricot•3mo ago
There seems to be defaultSsr: boolean in the main router options but the type for it is omitted for some reason 🤔
Omit<RouterOptions<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory, TDehydrated>, 'context' | 'serializationAdapters' | 'defaultSsr'>
Omit<RouterOptions<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory, TDehydrated>, 'context' | 'serializationAdapters' | 'defaultSsr'>
@Manuel Schiller is this intentional that we cannot set defaultSsr: false with createRouter?
eastern-cyan
eastern-cyan•3mo ago
yes. but this is now fixed for router.
eastern-cyan
eastern-cyan•3mo ago
GitHub
Release v1.132.7 · TanStack/router
Version 1.132.7 - 9/25/25, 3:29 PM Changes Fix opt into SSR type level serializability check (#5233) (e6ef218) by Manuel Schiller Packages @tanstack/router-core@1.132.7 @tanstack/start-plugin-co...
funny-blue
funny-blue•2w ago
It would be really useful to have a route function we could use here to modify the client-side context for sub-routes, just like how beforeLoad behaves when SSR is off.
eastern-cyan
eastern-cyan•2w ago
can you please create a new entry in #router-questions and explain in detail what you need?
funny-blue
funny-blue•2w ago
Thanks for the reply @Manuel Schiller! Sure thing - I've just written a post there: https://discord.com/channels/719702312431386674/1438983375582138529

Did you find this page helpful?