AbortError/AbortController with fetch: Setting reason of abort-signal breaks name and message of the thrown exception
Categories
(Core :: DOM: Networking, defect)
Tracking
()
People
(Reporter: stig, Unassigned)
References
Details
(Keywords: dev-doc-needed)
Attachments
(1 file)
3.05 KB,
text/html
|
Details |
User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0
Steps to reproduce:
I use AbortController to abort a fetch (on timeout).
When I do an abort without specifying a reason for the abortion, everything still works as usual and expected.
However when setting a reason for the abort it has started to behave differently and - I believe - wrong.
From Firefox 109 the thrown exception (when setting abort-reason) doesn't seem to be correctly initiated. Both name and message properties are undefined in the exception.
I'm guessing that checkin from bug #1793736 might be related to this issue?
I have created code to demonstrate it (I will also attach test-page to the bug) :
(async function test() {
const url = "https://jsonplaceholder.typicode.com/posts";
const controller = new AbortController();
// *** With no reason specified, it still works as expected: ***
// const timeoutId = setTimeout(() => controller.abort(), 2); /* 2ms to abort fetch */
// *** But if specifying reason, it breaks properties of the exception since Firefox version 109: ***
const timeoutId = setTimeout(() => controller.abort('AbortByTimeout'), 2); /* 2ms to abort fetch */
try {
const res = await fetch(url, {signal: controller.signal});
const body = await res.json();
} catch (error) {
console.log(`ERROR! Type/name: ${error.name}, Message: ${error.message}, Reason: ${controller.signal.reason}\nError: \n${error}`);
} finally {
clearTimeout(timeoutId);
}
})();
Actual results:
I have tested with Chrome 109, Firefox 108, Firefox 109 and Firefox 110 Beta (Dev.Ed.).
And I ran test both with and without the reason specified when aborting.
Without the reason specified all browsers behave as usual and I believe correctly.
With the reason specified, Chrome 109 and Firefox 108 behaves as usual and I believe correctly. But with Firefox 109+ name and message properties of thrown exception is undefined. The toString() value doesn't look correct or as expected either.
My test-results:
*** My results with abort signal reason specified ***
Firefox 110 Beta (Dev.Ed.)
ERROR! Type/name: undefined, Message: undefined, Reason: AbortByTimeout
Error:
AbortByTimeout
Firefox 109
ERROR! Type/name: undefined, Message: undefined, Reason: AbortByTimeout
Error:
AbortByTimeout
Firefox 108
ERROR! Type/name: AbortError, Message: The operation was aborted. , Reason: AbortByTimeout
Error:
AbortError: The operation was aborted.
Chrome 109
ERROR! Type/name: AbortError, Message: The user aborted a request., Reason: AbortByTimeout
Error:
AbortError: The user aborted a request.
*** My results without abort signal reason ***
Firefox 110 Beta (Dev.Ed.)
ERROR! Type/name: AbortError, Message: The operation was aborted. , Reason: AbortError: The operation was aborted.
Error:
AbortError: The operation was aborted.
Firefox 109
ERROR! Type/name: AbortError, Message: The operation was aborted. , Reason: AbortError: The operation was aborted.
Error:
AbortError: The operation was aborted.
Firefox 108
ERROR! Type/name: AbortError, Message: The operation was aborted. , Reason: AbortError: The operation was aborted.
Error:
AbortError: The operation was aborted.
Chrome 109
ERROR! Type/name: AbortError, Message: The user aborted a request., Reason: AbortError: signal is aborted without reason
Error:
AbortError: The user aborted a request.
Comment 1•2 years ago
|
||
The Bugbug bot thinks this bug should belong to the 'Core::DOM: Networking' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.
The thrown exception is the reason you specified, in this case the string "AbortByTimeout"
. That is also why it doesn't have the properties name and message. Chrome doesn't implement this part of the specification.
Reporter | ||
Comment 3•2 years ago
|
||
(In reply to Tom S [:evilpie] from comment #2)
The thrown exception is the reason you specified, in this case the string
"AbortByTimeout"
. That is also why it doesn't have the properties name and message. Chrome doesn't implement this part of the specification.
Thanks for explanation. So what I see in Firefox 109+ is actually correct by specification? I have never thought of the reason to be the actual exception to throw, but makes somehow sense.
But I think MDN needs an update on all related documentation-pages to make things clearer/correct. Including the Browser Compatibility Charts which all says both Chrome and Firefox has been following standards for a while.
While re-visiting the MDN documentation, I btw. discovered AbortSignal.timeout() which probably better suits my purpose (makes it simpler). But also that have documentation problems. While I can abort using this in latest versions of Firefox and Chrome, only Firefox throws the "TimeoutError" exception. Chrome throws the "AbortError" exception (I'm guessing older Firefox versions does same?). Yet documentation says both Chrome and Firefox have been following standard for some time on this.
PS. So what do I do with this bug? Do I resolve it as "INVALID" (If I'm allowed to do that myself)?
Kagami, can you just verify and close this if appropriate?
Comment 5•2 years ago
|
||
https://github.com/whatwg/fetch/pull/1343 that changed this was submitted in nov 2022 - so it's only reasonable that not all browsers have implemented it yet.
I think MDN docs need to be updated.
Comment 6•2 years ago
|
||
(In reply to Tom S [:evilpie] from comment #2)
The thrown exception is the reason you specified, in this case the string
"AbortByTimeout"
. That is also why it doesn't have the properties name and message. Chrome doesn't implement this part of the specification.
That's right. See also this minimal AbortSignal use:
controller = new AbortController()
signal = controller.signal
signal.onabort = () => console.log(signal.reason)
controller.abort()
// controller.abort("reason")
With pure .abort()
the signal.reason
becomes a DOMException object, while with .abort("reason")
it becomes a string. You need to pass new DOMException("your reason", "AbortError")
if you want to keep it a DOMException.
(In reply to Stig Nygaard from comment #3)
While I can abort using this in latest versions of Firefox and Chrome, only Firefox throws the "TimeoutError" exception. Chrome throws the "AbortError" exception (I'm guessing older Firefox versions does same?). Yet documentation says both Chrome and Firefox have been following standard for some time on this.
Per the spec it should be TimeoutError
. I guess Chrome properly throws TimeoutError from AbortSignal but then is not properly passing it to Fetch, as others already noted.
Description
•