You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Router context invalidate Promise resolve does not invalidate context #2072
In the code below, which was suppose to invalidate the context and navigate to the following route. for context i'm following the example given in tanstack authenticated routes example. Even after navigation the context isn't invalidated which I can see in console log. It results in redirect to login page not working properly after clicking logout and just stuck in the "/" page.
router.invalidate().finally(() => { navigate({ to: "/" }); });
It only invalidates or I can see it invalidates when I manually reload the page, which means during the navigation the context doesn't invalidate.
PS: I do have an api request in the logout function.
Router context should've been already invalid in .finally or .then even before navigating.
Screenshots or Videos
No response
Platform
OS: [e.g. macOS, Windows, Linux]
Browser: [e.g. Chrome, Safari, Firefox]
Version: [e.g. 91.1]
Additional context
No response
Reacted by Jake Correa, Mohamed Khennoussi, Ilia luk, Vincent Delmas, Constantin Druc, Hubert Kaźmierczak, Christian Pannwitz, Janek Thomaschewski, Ibrahim YTL, Ricky and 17 more
i got same issue, and stuck with this, any solution ? when i am use authenticated using local storage, there is no problem, but when using api, not navigate after login success
i got same issue, and stuck with this, any solution ? when i am use authenticated using local storage, there is no problem, but when using api, not navigate after login success
Here a link to a fork, I've only made one change to this, instead of navigating to "/" which is a public route, it navigates to "login", which shouldn't be a problem if context is invalidated, however it isn't. so even after clicking logout, it doesn't go back to "login" route.
I've noticed that the issue was not there in version 1.16.0 of @tanstack/react-router, but it was found in the latest release, version 1.56.1. Could you provide a proper solution or let us know if there is a patch release available?
Same here. I am updating the context passed to the router, but while the context's value gets updated correctly, the loader functions that are triggered with router.invalidate() still load the older context value.
Only when the route is reloaded manually the router shows the updated context.
I've tried doing this with any given combination of useState, useEffect and contextProvider and still same result.
As others have mentioned, a workaround for this involves using some kind of synchronous external store instead of the router context (in my case, I am using Tanstack Query, so I am grabbing the queryClient from the router context and using queryClient.getQueryData to get the updated value).
This approach ensures that authentication status is always checked based on updated state. However, it would be great to have a proper fix for beforeLoad so that context updates correctly after router.invalidate().
I reproduced the original report with a public-API test: a pathless _authenticated route whose beforeLoad reads context.auth.isAuthenticated and throws redirect({ to: '/login' }), with auth supplied via RouterProvider context={{ auth }}. Logging out sets the auth state and calls router.invalidate() in the same event handler.
On @tanstack/react-router@1.170.39 (fix first released in 1.170.32), beforeLoad observes the fresh context ([true, false]) and the redirect to /login happens; the inverse (login -> /private) also works.
This was fixed by #8130 ("preserve context during reloads", merged 2026-08-20, released in @tanstack/react-router@1.170.32), which also added the issue-8115-context suite. The exact same-handler ordering (setState + invalidate() together) isn't covered by #8115, so I can open a small regression-test PR if useful - otherwise I think this can be closed as fixed.
I don't think this is fixed. The test above calls setState and invalidate() in the same handler. That case already worked before #8130 (it passes on 1.170.23 too). The original report has an API call before the state update. With that, on 1.170.35 the beforeLoad and loader run by invalidate() still see the old context:
// auth comes from useState, passed via <RouterProvider context={{ auth }} />// _authenticated beforeLoad: if (!context.auth.isAuthenticated) throw redirect({ to: '/login' })awaitapi()// any await before the state updatesetIsAuthenticated(false)awaitrouter.invalidate()// beforeLoad + loader see isAuthenticated: true
With a trailing navigate() (as in the original report) the next load picks up the new context. That masks the problem, but the context is still stale when invalidate() resolves, which is what this issue is about. Without navigate() the user stays on /, logged out. It behaves the same on 1.170.23 and 1.170.35.
I don't think this is fixed. The test above calls setState and invalidate() in the same handler. That case already worked before #8130 (it passes on 1.170.23 too). The original report has an API call before the state update. With that, on 1.170.35 the beforeLoad and loader run by invalidate() still see the old context:
// auth comes from useState, passed via <RouterProvider context={{ auth }} />
// _authenticated beforeLoad: if (!context.auth.isAuthenticated) throw redirect({ to: '/login' })
await api() // any await before the state update
setIsAuthenticated(false)
await router.invalidate() // beforeLoad + loader see isAuthenticated: true
With a trailing navigate() (as in the original report) the next load picks up the new context. That masks the problem, but the context is still stale when invalidate() resolves, which is what this issue is about. Without navigate() the user stays on /, logged out. It behaves the same on 1.170.23 and 1.170.35.
Could this be reopened?
Could you PR a minimal reproduction of the issue? (kind of what #8499 did)
(open dev console once you log in, do a logout and you will see that the _authenticated route's beforeload will still have the stale context when it runs)
(open dev console once you log in, do a logout and you will see that the _authenticated route's beforeload will still have the stale context when it runs)
On main, _authenticated's beforeLoad sees [true, true] instead of [true, false], so the redirect to /login never happens.
@mkarajohn your repro passes on 1.170.32 because its logout navigates afterwards, and that next load picks up the fresh context. The load triggered by invalidate() itself still sees the stale one.
to me it makes sense that router.invalidate() isn't aware of setIsAuthenticated(false) since react updates it later. I don't think we should expect it to "wait for the next render when called".
Fair point: invalidate() can't know about a state update React hasn't rendered yet, and expecting it to wait for a render isn't reasonable. I'm fine treating that as by design.
which runs outside a React event handler, so it hits exactly this. The authenticated-routes example works around it with await sleep(1) ("just a hack being used to wait for the auth state to update"). Maybe some doc adjustments could help here.
Activity
robertyulisman commentedon Aug 9, 2024
i got same issue, and stuck with this, any solution ? when i am use authenticated using local storage, there is no problem, but when using api, not navigate after login success
ZahidHasan321 commentedon Aug 14, 2024
Still no reply from the devs as of now
ilia-luk commentedon Aug 20, 2024
same issue here
schiller-manuel commentedon Aug 20, 2024
can you please provide a minimal complete example by forking one of the router examples on stackblitz?
ZahidHasan321 commentedon Aug 20, 2024
https://stackblitz.com/edit/tanstack-router-4achrw?file=src%2Froutes%2F_auth.tsx
Here a link to a fork, I've only made one change to this, instead of navigating to "/" which is a public route, it navigates to "login", which shouldn't be a problem if context is invalidated, however it isn't. so even after clicking logout, it doesn't go back to "login" route.
mkhennoussi commentedon Aug 22, 2024
Same here while using supabase auth api. No issue when working with local storage.
This is not working : https://tanstack.com/router/latest/docs/framework/react/guide/router-context#invalidating-the-router-context
mkhennoussi commentedon Aug 22, 2024
update guys, the current hack seems to use
sleep(1000)as explained here :#1668
This trick works on my side, but this is a serious issue with Context.
PS: the sleep function is quite obvious :
ilia-luk commentedon Aug 23, 2024
I'm currently using the flushSync solution as a workaround following suggestion by SzelamC at #1668 (reply in thread)
ZahidHasan321 commentedon Aug 23, 2024
So where should I use flushSync regarding this issue?
mkhennoussi commentedon Aug 23, 2024
Thanks @ilia-luk, it works great, I didn't thought about this solution.
@ZahidHasan321 use flushSync in your AuthProvider when you set your new user/session state like in the thread mentionned by @ilia-luk .
syama-aot commentedon Sep 6, 2024
I've noticed that the issue was not there in version 1.16.0 of @tanstack/react-router, but it was found in the latest release, version 1.56.1. Could you provide a proper solution or let us know if there is a patch release available?
joemark0008 commentedon Jan 11, 2025
Got same issue here
"@tanstack/react-router": "^1.95.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
Rick-Phoenix commentedon Jan 14, 2025
Same here. I am updating the context passed to the router, but while the context's value gets updated correctly, the loader functions that are triggered with router.invalidate() still load the older context value.
Only when the route is reloaded manually the router shows the updated context.
I've tried doing this with any given combination of useState, useEffect and contextProvider and still same result.
As others have mentioned, a workaround for this involves using some kind of synchronous external store instead of the router context (in my case, I am using Tanstack Query, so I am grabbing the queryClient from the router context and using queryClient.getQueryData to get the updated value).
Fix router context not updating upon successful login (TanStack/route…
CyrilStrone commentedon Mar 14, 2025
I also encountered this problem and found that context does not always update correctly when calling router.invalidate().
Previously, I used beforeLoad like this:
However, I noticed that context does not always update properly after router.invalidate().
As a temporary workaround, I moved the authentication check to the root component like this:
This approach ensures that authentication status is always checked based on updated state. However, it would be great to have a proper fix for beforeLoad so that context updates correctly after router.invalidate().
13 remaining items
fix(ui): Update the cache on rename instead of reloading the page
fix(ui): Update the cache on rename instead of reloading the page
CyrilStrone commentedon Sep 25, 2026
Confirming this is fixed on current main.
I reproduced the original report with a public-API test: a pathless
_authenticatedroute whosebeforeLoadreadscontext.auth.isAuthenticatedand throwsredirect({ to: '/login' }), with auth supplied viaRouterProvider context={{ auth }}. Logging out sets the auth state and callsrouter.invalidate()in the same event handler.On
@tanstack/react-router@1.170.39(fix first released in1.170.32),beforeLoadobserves the fresh context ([true, false]) and the redirect to/loginhappens; the inverse (login ->/private) also works.This was fixed by #8130 ("preserve context during reloads", merged 2026-08-20, released in
@tanstack/react-router@1.170.32), which also added theissue-8115-contextsuite. The exact same-handler ordering (setState+invalidate()together) isn't covered by #8115, so I can open a small regression-test PR if useful - otherwise I think this can be closed as fixed.test(react-router): drive TanStack#2072 login redirect via beforeLoad
test(react-router): regression for #2072 router context invalidation (#…
SiKreuz commentedon Sep 29, 2026
I don't think this is fixed. The test above calls
setStateandinvalidate()in the same handler. That case already worked before #8130 (it passes on 1.170.23 too). The original report has an API call before the state update. With that, on 1.170.35 thebeforeLoadand loader run byinvalidate()still see the old context:With a trailing
navigate()(as in the original report) the next load picks up the new context. That masks the problem, but the context is still stale wheninvalidate()resolves, which is what this issue is about. Withoutnavigate()the user stays on/, logged out. It behaves the same on 1.170.23 and 1.170.35.Could this be reopened?
Sheraff commentedon Sep 29, 2026
Could you PR a minimal reproduction of the issue? (kind of what #8499 did)
mkarajohn commentedon Sep 29, 2026
I had a pre-1.170.32 repro here: #2072 (comment)
(open dev console once you log in, do a logout and you will see that the _authenticated route's beforeload will still have the stale context when it runs)
I forked it and updated to 1.170.32, here: https://stackblitz.com/edit/tanstack-router-c3dgcdre?file=package.json
if you follow the same steps, the aforementioned beforeload, has the correct context on logout now.
I have not followed what changed internally, but as an end user it works as expected now
Sheraff commentedon Sep 29, 2026
sorry I meant to ask for an actual PR of a test that isolates the issue
SiKreuz commentedon Oct 1, 2026
Here it is: #8575
It adds one test next to the #8499 ones. The only difference is an awaited request before the state update, with no
navigate()afterwards:On
main,_authenticated'sbeforeLoadsees[true, true]instead of[true, false], so the redirect to/loginnever happens.@mkarajohn your repro passes on 1.170.32 because its logout navigates afterwards, and that next load picks up the fresh context. The load triggered by
invalidate()itself still sees the stale one.SiKreuz commentedon Oct 14, 2026
@Sheraff did you have any time to look into the small repro? #8575
Sheraff commentedon Oct 14, 2026
no sorry. But looking at the example right now:
to me it makes sense that
router.invalidate()isn't aware ofsetIsAuthenticated(false)since react updates it later. I don't think we should expect it to "wait for the next render when called".SiKreuz commentedon Oct 21, 2026
Fair point:
invalidate()can't know about a state update React hasn't rendered yet, and expecting it to wait for a render isn't reasonable. I'm fine treating that as by design.But that's the pattern the docs recommend. The React example under Invalidating the Router Context does
which runs outside a React event handler, so it hits exactly this. The
authenticated-routesexample works around it withawait sleep(1)("just a hack being used to wait for the auth state to update"). Maybe some doc adjustments could help here.