T
TanStack6mo ago
distinguished-blush

Loader and interceptors

Hi guys, I've encountered an unexpected behavior (at least for me) when using TanStack Router. When I make an asynchronous call to an API inside a loader, and the API responds with a 401 Unauthorized due to an expired access token, I expect my Axios interceptors to handle this (as they do correctly with useQuery, useMutation, etc.). However, it seems that the error is caught by the router’s error handling mechanism before the interceptor has a chance to process it. As a result, logic such as token refreshing, user sign-out, or redirecting doesn’t happen. Is this expected behavior? If so, is there a recommended pattern to allow Axios interceptors to work correctly with loader-based API calls?
24 Replies
extended-salmon
extended-salmon6mo ago
does the loader throw an error? then router will handle it
distinguished-blush
distinguished-blushOP6mo ago
Yes it does, and yes, router display it's own default errorComponent but why the interceptors are not handling error first? It looks like error handler from router does it first, before response interceptors
extended-salmon
extended-salmon6mo ago
how did you install your interceptors? you need to prevent the loader to throw an error if you handle it yourself
distinguished-blush
distinguished-blushOP6mo ago
my interceptors are installed here in authprovider in useLayoutEffect hook
No description
extended-salmon
extended-salmon6mo ago
ah well
distinguished-blush
distinguished-blushOP6mo ago
atleast those responsible for auth mechanism
extended-salmon
extended-salmon6mo ago
a loader does not execute inside of the react world so your react interceptors cannot handle that or maybe I misunderstood do you think the response interceptors are not installed yet?
distinguished-blush
distinguished-blushOP6mo ago
i think you might be right i'm installing some of interceptors here and some interceptors direct in axios instance i wanted to add possibility to interact with UI from interceptors (show snackbar for example) and this can be done only by installing interceptors in some context provider which has access to other context providers On image for example authprovider has access to things from snackbarprovider
extended-salmon
extended-salmon6mo ago
so is it a timing issue now? the interceptors not installed before the error occurs in router?
distinguished-blush
distinguished-blushOP6mo ago
i think as you said "a loader does not execute inside of the react world", so the interceptors registered in react hooks doesn't work Am i right?
extended-salmon
extended-salmon6mo ago
no i misunderstood your setup your axios instance also lives outside react kinda it is not a react managed component or depends on react rendering so if the interceptors are installed as here https://axios-http.com/docs/interceptors then I dont see a reason why the loader would throw
distinguished-blush
distinguished-blushOP6mo ago
oke so i have this axios.ts file which creates instance
export const axiosClient = axios.create({
baseURL: '/api',
headers: {
'Content-Type': 'application/json',
pragma: 'no-cache',
'cache-control': 'no-cache'
},
paramsSerializer: {
indexes: null
}
});
export const axiosClient = axios.create({
baseURL: '/api',
headers: {
'Content-Type': 'application/json',
pragma: 'no-cache',
'cache-control': 'no-cache'
},
paramsSerializer: {
indexes: null
}
});
but the interceptors are not installed here. They are installed in mentioned AuthProvider like this
export const WAuthProvider = ({ children }: PropsWithChildren<unknown>) => {
const snackbar = useSnackbar();
useLayoutEffect(() => {
const refreshInterceptor = axiosClient.interceptors.response.use(
async response => {
snackbar.show('somemessage');
}
);
return () => axiosClient.interceptors.request.eject(authInterceptor);
}
}
export const WAuthProvider = ({ children }: PropsWithChildren<unknown>) => {
const snackbar = useSnackbar();
useLayoutEffect(() => {
const refreshInterceptor = axiosClient.interceptors.response.use(
async response => {
snackbar.show('somemessage');
}
);
return () => axiosClient.interceptors.request.eject(authInterceptor);
}
}
extended-salmon
extended-salmon6mo ago
so when does the error occur? has the auth provider been rendered already?
distinguished-blush
distinguished-blushOP6mo ago
my guess is no. Because i tried to log some stuff in this provider and didn't see any log in console wait
distinguished-blush
distinguished-blushOP6mo ago
it is rendering, i put some more logs
No description
extended-salmon
extended-salmon6mo ago
but your interceptor does not prevent the error to be thrown?
distinguished-blush
distinguished-blushOP6mo ago
yep it should hit /refresh, then after achieving new token hit /orders again
distinguished-blush
distinguished-blushOP6mo ago
No description
extended-salmon
extended-salmon6mo ago
looks like you need to install two functions in the interceptor? https://axios-http.com/docs/interceptors
distinguished-blush
distinguished-blushOP6mo ago
ah sorry, i have the other one too, just didn't copy it there goddamn i noticed something but you pointed it out 😄 thanks for help, i had a very hard to find problem with interceptor logic
extended-salmon
extended-salmon6mo ago
what was the issue now?
distinguished-blush
distinguished-blushOP6mo ago
my bad, i have some weird logic on backend that api validates public request's and shows info about expired token not in error response but in header which i didn't handle properly
extended-salmon
extended-salmon6mo ago
so all working now?
distinguished-blush
distinguished-blushOP6mo ago
yes, issue closed Thanks for help

Did you find this page helpful?