T
TanStack10mo ago
absent-sapphire

useMutation onError never triggered?

I am experiencing an issue with useMutation in my custom hook. The onError logic is never getting triggered, the onSuccess is. The hook (throws on error 1/3, random):
import { useMutation } from '@tanstack/react-query';

const SONGS = ['Eine Woche wach', 'Ich bin solo'];

const sing = async () => {
if (Math.random() < 1 / 3) {
throw new Error('Mickie Krause forgot the lyrics!');
}
return SONGS[Math.floor(Math.random() * SONGS.length)];
};

const useMickieKrause = () => {
return useMutation({
mutationFn: sing,
onSuccess: (song) => {
console.log(`Mickie Krause is singing: ${song}`);
},
onError: (error) => {
console.log(`Mickie Krause had an error: ${error}`);
},
});
};

export { useMickieKrause };
import { useMutation } from '@tanstack/react-query';

const SONGS = ['Eine Woche wach', 'Ich bin solo'];

const sing = async () => {
if (Math.random() < 1 / 3) {
throw new Error('Mickie Krause forgot the lyrics!');
}
return SONGS[Math.floor(Math.random() * SONGS.length)];
};

const useMickieKrause = () => {
return useMutation({
mutationFn: sing,
onSuccess: (song) => {
console.log(`Mickie Krause is singing: ${song}`);
},
onError: (error) => {
console.log(`Mickie Krause had an error: ${error}`);
},
});
};

export { useMickieKrause };
I only see Mickie Krause is singing... messages. Any help would be appreciated.
11 Replies
rival-black
rival-black10mo ago
mutationFn: A function that performs an asynchronous task and returns a promise.
You are not returning a Promise from the sing-function
absent-sapphire
absent-sapphireOP10mo ago
Am I not? IntelliJ marked my method as returning a promise of a string (implicit typing)
No description
absent-sapphire
absent-sapphireOP10mo ago
In the course I've read the following: "In fact, whether you throw an error, call the reject method for a manually-constructed promise, or return the results of Promise.reject() – any promise rejection tells React Query that an error occurred and to set the status of the query to error." So I was under the impression that throwing an error would trigger the hook level onError. I just tried manually rejecting the promise but got the same result, only on component level the onError is triggered, the one on hook level is ignored.
await Promise.reject('Mickie Krause forgot the lyrics!');
await Promise.reject('Mickie Krause forgot the lyrics!');
fair-rose
fair-rose10mo ago
async functions always return a promise. Your code looks fine to me
absent-sapphire
absent-sapphireOP10mo ago
Any idea what could be causing this? I just checked our version, we are on 5.59.13
fair-rose
fair-rose10mo ago
React Query FAQs
Answering the most frequently asked React Query questions
absent-sapphire
absent-sapphireOP10mo ago
@TkDodo 🔮 I think we have a stable client (wrapped inside a provider component) using useEffect. I did however noticed a possible issue:
const [client] = React.useState(
() =>
new QueryClient({
queryCache: new QueryCache({
onError: (error) => {
handleError(error);
},
}),
mutationCache: new MutationCache({
onError: (error) => {
handleError(error);
},
}),
}),
);
const [client] = React.useState(
() =>
new QueryClient({
queryCache: new QueryCache({
onError: (error) => {
handleError(error);
},
}),
mutationCache: new MutationCache({
onError: (error) => {
handleError(error);
},
}),
}),
);
If I remove the onError of the mutationCache property, I can see the hook onError being triggered, is this expected behaviour? Anyone else knows if the above behavior is expected?
fair-rose
fair-rose10mo ago
no, the callbacks from the cache don't overwrite the one on useMutation. Try to create a minimal reproduction in stackblitz please
absent-sapphire
absent-sapphireOP10mo ago
Will try to do so this evening. In case I can reproduce it over there, should I create an issue directly or keep the discussion going on here?
fair-rose
fair-rose10mo ago
If you can reproduce something in a sandbox, feel free to create an issue
absent-sapphire
absent-sapphireOP10mo ago
I think I found the culprit, my handleError method that I call within the onError of mutationCache > onError:
const handleError = (error: Error) => {
if (error instanceof UnauthorizedError) {
...
} else throw error;
};
const handleError = (error: Error) => {
if (error instanceof UnauthorizedError) {
...
} else throw error;
};
I was under the impression (no idea why) I needed to rethrow the error. Doing so causes the onError on hook level to not work anymore.

Did you find this page helpful?