In my react application I'm doing a simple fetch inside my useEffect
.
useEffect(() => {
async function fetchData() {
const res = await fetch(
"https://api-production.afghantell.com/apiv1/eligibilities",
);
console.log(res.status);
console.log(res.headers);
}
fetchData();
}, []);
Everything is good when the response is successful. But I can't access res
when the request fails for example with a 400 Error, Even using try catch blocks wasn't any help. There is a specific X-reason
attribute in this failed fetch response that I need to access but I can't.
For comprehensive error handling for fetch
you have to consider both a rejected promise, and an unsuccessful network request. MDN wrote it better than I can...
A fetch() promise only rejects when the request fails, for example, because of a badly-formed request URL or a network error. A fetch() promise does not reject if the server responds with HTTP status codes that indicate errors (404, 504, etc.). Instead, a then() handler must check the Response.ok and/or Response.status properties.
So keep in mind that if the request was not sent, there will be no Response
object to inspect. So for example, if you make a request to a completely fake, made-up URL, the DNS lookup will fail...
try {
const response = await fetch('https://some.thing.made.up.com')
} catch (err) {
console.log('Here is your error', err);
}
This produces the output :
Here is your error TypeError: fetch failed
at node:internal/deps/undici/undici:12618:11
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async file:///Volumes/path/to/sample.js:2:22 {
cause: Error: getaddrinfo ENOTFOUND some.thing.made.up.com
at GetAddrInfoReqWrap.onlookupall [as oncomplete] (node:dns:118:26) {
errno: -3008,
code: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'some.thing.made.up.com'
}
}
So for the above case, you cannot inspect the headers, because there are none to speak of. Note the err
object in the catch
block should be an instance of Error
, but it could be several types of error depending on what happened, such as TypeError
or AggregateError
. From the OP's post, it seems like this is what happened.
If the requests fail with some status code, eg. 400 or 500 series error, you can inspect the Response object to get more information about what went wrong.
try {
const response = await fetch('https://www.google.com/bad/url')
console.log('my status code...', response.status);
console.log('my date header...', response.headers.get('date'));
} catch (err) {
console.log('Here is your error', err);
}
outputs...
my status code... 404
my date header... Mon, 05 May 2025 16:30:40 GMT
Note that I used Node for these examples. In the browser you will get different behavior, but the same concept applies. Unfortunately, this can be confusing, especially in cases of CORS errors, because (at least in Chrome) you will see the request in the Network panel, however, the code will skip right to the catch block, and you will not be able to inspect the response headers.
useEffect(() => {
async function fetchData() {
try {
const res = await fetch('https://www.google.com/');
console.log('This is never gonna happen', res.status);
} catch(err) {
console.log('Catching TypeError, but I can see CORS error in console', err);
}
}
fetchData();
}, []);