'response.json() throws "TypeError: Failed to fetch"
I use fetch for getting some resources from the server. I can see from logs that from time to time conversion to JSON fails on "TypeError: Failed to fetch"
which is very interesting because this type of error should only happen when the request fails.
The simplified code I use:
const response = await fetch('https://something.com/api')
try {
await response.json() // -> throws TypeError: Failed to fetch in chrome/safari and throws AbortError in Firefox
} catch(error) {
console.log('error happened', error);
}
I cannot really find the case when it might happen. I tested possible cases and all failed on the first line of code, i.e. fetch('https:/something.com/api')
. I have no idea when this might happen. I also should mention that it happens in modern browsers like chrome 99. So it is not definitely something like internet explorer thing.
I found this useful example and it shows that requests are cancelled when you unload the document. Obviously, cancellation happens on the fetch
line but I decided to stop logging these errors when the document is unloaded/hidden. Even when these cases are not logged I can see it happens on visible documents too.
https://github.com/shuding/request-cancellation-test
Cases tested:
- Network error - user disconnected from the internet
- CORS - missing CORS headers
Obviously, this does not prove anything but people in the comments think that I do something wrong in implementation and do not trust me when I say it indeed happens when converting to json. This is the information I am able to log when I catch the error. Most properties are from the Response object.
This is the log captured from visitor using chrome 100. Firefox does not throw TypeError instead it throws AbortError but it also happens when converting to json.
Solution 1:[1]
This looks like a network error that happened after the response HTTP headers have already been received. In such a situation, the fetch
method returns success, but subsequent attempts to access the response body may fail.
I managed to trigger this kind of error with this simple server:
#!/usr/bin/env python3
import http.server
import time
class Handler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/':
self.wfile.write(b'HTTP/1.0 200 OK\r\n')
self.wfile.write(b'Content-type: text/html\r\n')
self.wfile.write(b'\r\n')
self.wfile.write(b"""\
<script type="module">
const f = await fetch("/j");
try {
await f.json();
} catch (e) {
alert(e);
}
</script>
""")
return
self.wfile.write(b'HTTP/1.0 200 OK\r\n')
self.wfile.write(b'Content-encoding: gzip\r\n') # bogus
self.wfile.write(b'Content-type: application/json\r\n')
self.wfile.write(b'\r\n')
self.wfile.write(b'[]')
server = http.server.HTTPServer(('127.0.0.1', 31337), Handler)
server.serve_forever()
It introduces a deliberate framing error when serving the JSON response; the headers indicate that gzip compression is employed, but no compression is actually used. When I open http://127.0.0.1:31337/
in Chromium 100.0.4896.127, it displays the following alert:
TypeError: Failed to fetch
Firefox ESR 91.8.0 displays a marginally more helpful:
TypeError: Decoding failed.
The particular framing error demonstrated above is rather contrived, and I doubt it is exactly the kind that the asker experienced. But the fact that it appeared in the middle of the response body is probably at the heart of the described problem.
The specific pair of error types from the question can be triggered by modifying the server thus:
self.wfile.write(b'HTTP/1.1 200 OK\r\n')
self.wfile.write(b'Content-type: application/json\r\n')
# sic: larger than the actual body length
self.wfile.write(b'Content-length: 2\r\n')
self.wfile.write(b'\r\n')
self.wfile.write(b'[')
This displays the same alert:
TypeError: Failed to fetch
in Chromium (same version), and
AbortError: The operation was aborted.
in Firefox (also same).
As such, a likely cause would be a flaky connection dropped in the middle of receiving the body. The browsers’ errors are not particularly detailed here (and sometimes are downright misleading), so we are resigned to speculate, but this seems like the best guess.
Solution 2:[2]
Your error from this line:
const response = await fetch('https://something.com/api')
I removed await response.json()
to test, the error still exists.
Please look console tab in DevTool, make sure that you use this setting
These are 2 example errors Failed to fetch
:
(async () => {
try {
const response = await fetch('http://my-api.com/example')
await response.json()
} catch (e) {
console.log('e')
console.log(e)
}
})()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | hong4rc |