T
TanStack•2w ago
ambitious-aqua

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...
21 Replies
dependent-tan
dependent-tan•2w 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
ambitious-aqua
ambitious-aquaOP•2w ago
No description
ambitious-aqua
ambitious-aquaOP•2w 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
dependent-tan
dependent-tan•2w 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 ?
ambitious-aqua
ambitious-aquaOP•2w 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
dependent-tan
dependent-tan•2w 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
ambitious-aqua
ambitious-aquaOP•2w 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
dependent-tan
dependent-tan•2w 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
ambitious-aqua
ambitious-aquaOP•2w ago
Also one more important distinction. Types break, code continues to work just fine
dependent-tan
dependent-tan•2w ago
there might be some type issue then, you're probably right
ambitious-aqua
ambitious-aquaOP•2w 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
dependent-tan
dependent-tan•2w ago
i see
ambitious-aqua
ambitious-aquaOP•2w ago
there might be some type issue then, you're probably right
correct
dependent-tan
dependent-tan•2w ago
file an issue on gh
jolly-crimson
jolly-crimson•2w 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
ambitious-aqua
ambitious-aquaOP•2w 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
dependent-tan
dependent-tan•2w 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)
ambitious-aqua
ambitious-aquaOP•2w 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
jolly-crimson
jolly-crimson•2w 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?
correct-apricot
correct-apricot•2w ago
yes. but this is now fixed for router.
correct-apricot
correct-apricot•2w 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...

Did you find this page helpful?