Unexpected "uncaught exception" using async functions Topic is solved

Talk about code development, features, specific bugs, enhancements, patches, and similar things.
Forum rules
Please keep everything here strictly on-topic.
This board is meant for Pale Moon source code development related subjects only like code snippets, patches, specific bugs, git, the repositories, etc.

This is not for tech support! Please do not post tech support questions in the "Development" board!
Please make sure not to use this board for support questions. Please post issues with specific websites, extensions, etc. in the relevant boards for those topics.

Please keep things on-topic as this forum will be used for reference for Pale Moon development. Expect topics that aren't relevant as such to be moved or deleted.
SemiKebab
Moonbather
Moonbather
Posts: 50
Joined: 2021-05-30, 03:48

Unexpected "uncaught exception" using async functions

Unread post by SemiKebab » 2024-01-03, 17:15

I was having a hard time understanding why I was getting "uncaught exception" errors in the console, although the promise reject was actually caught and my code was running as expected.

Upon investigation, I discovered the error was not happening on other browsers, and it seems to be a bug in Pale Moon.

Code: Select all

document.body.addEventListener('click', async function () {
    async function usingThrow() {
        throw Error('Using throw');
    }
    await usingThrow().catch(err => console.log('Caught: ' + err));
});

document.body.addEventListener('click', async function () {
    async function usingPromiseReject() {
        return Promise.reject('Using Promise.reject');
    }
    await usingPromiseReject().catch(err => console.log('Caught: ' + err));
});
Results:
Caught: Using Promise.reject
Caught: Error: Using throw
uncaught exception: Using Promise.reject
Note this code also causes an error:

Code: Select all

document.body.addEventListener('click', async function () {
    async function usingPromiseReject() {
        return Promise.reject('Using Promise.reject');
    }
    await usingPromiseReject().catch(err => console.log('Caught: ' + err));

    async function usingThrow() {
        throw Error('Using throw');
    }
    await usingThrow().catch(err => console.log('Caught: ' + err));
});
But this one does not (I only reversed the order):

Code: Select all

document.body.addEventListener('click', async function () {
    async function usingThrow() {
        throw Error('Using throw');
    }
    await usingThrow().catch(err => console.log('Caught: ' + err));

    async function usingPromiseReject() {
        return Promise.reject('Using Promise.reject');
    }
    await usingPromiseReject().catch(err => console.log('Caught: ' + err));
});
Thus, I suspect there may be some race condition.

Additionally:
  • The error happens only when using an event handler. There is no error if directly executing the code.
  • For the code causing errors, sometimes there is no error on the first clicks.
As a reminder, in async functions, throws are converted to promise rejects. And in await calls, promise rejects are converted to exceptions. :P

Maybe a some point in the await call, the promise reject is converted to a throw, whereas it shouldn't be, as it is handled by the .catch(). And that "leftover throw" doesn't break execution, while still being logged.

SemiKebab
Moonbather
Moonbather
Posts: 50
Joined: 2021-05-30, 03:48

Re: Unexpected "uncaught exception" using async functions

Unread post by SemiKebab » 2024-01-04, 09:23

I did another test:

I though "if I enclose the problematic await call with a try/catch, that unexpected exception should at least be caught, right?".

Nope, even with the following code, an uncaught exception error happens:

Code: Select all

document.body.addEventListener('click', async function () {
    async function usingPromiseReject() {
        return Promise.reject('Using Promise.reject');
    }
    try {
        await usingPromiseReject().catch(err => console.log('Caught: ' + err));
    } catch (e) {
        console.log(e);
    }
});
Console:
Caught: Using Promise.reject
uncaught exception: Using Promise.reject
The first line is expected, it's the .catch() handler.
But the second line is totally unexpected. There should not be no exception at all, and even it we try to catch that unexpected exception, it doesn't succeed.
Last edited by SemiKebab on 2024-01-04, 09:32, edited 2 times in total.

SemiKebab
Moonbather
Moonbather
Posts: 50
Joined: 2021-05-30, 03:48

Re: Unexpected "uncaught exception" using async functions

Unread post by SemiKebab » 2024-01-04, 09:31

Another test:

Code: Select all

document.body.addEventListener('click', async function () {
    async function usingPromiseReject() {
        return Promise.reject('Using Promise.reject');
    }
    await usingPromiseReject().catch(err => console.log('Caught: ' + err));
    console.log('test');
});
Console:
Caught: Using Promise.reject
test
uncaught exception: Using Promise.reject
We have the usual "unexpected exception", but what's interesting is that the "test" is logged before it, which means the "await" instruction hasn't been respected :o (at least, in this particular case).

User avatar
Kris_88
Keeps coming back
Keeps coming back
Posts: 940
Joined: 2021-01-26, 11:18

Re: Unexpected "uncaught exception" using async functions

Unread post by Kris_88 » 2024-01-04, 10:19

Try this:

Code: Select all

<html>
<body>

<script>

((Promise) => {
  const originalThen = Promise.prototype.then;
  const originalCatch = Promise.prototype.catch;

  Promise.prototype.then = function (...args) {
    console.log("Called .then on %o with arguments: %o", this, args);
    return originalThen.apply(this, args);
  };
  Promise.prototype.catch = function (...args) {
    console.error("Called .catch on %o with arguments: %o", this, args);
    return originalCatch.apply(this, args);
  };
})(Promise);


document.body.addEventListener('click', async function () {
    async function usingPromiseReject() {
        return Promise.reject('Using Promise.reject');
    };

    await usingPromiseReject().catch(err => console.log('Caught: ' + err));
});

</script>
click
</body>
</html>

User avatar
Kris_88
Keeps coming back
Keeps coming back
Posts: 940
Joined: 2021-01-26, 11:18

Re: Unexpected "uncaught exception" using async functions

Unread post by Kris_88 » 2024-01-04, 12:04

PM32.5.2

Code: Select all

Called .catch on  Promise { <state>: "pending" }  with arguments:  Array [ function (err) ]  a.htm:15:13
Called .then on  Promise { <state>: "pending" }  with arguments:  Array [ undefined, function (err) ]  a.htm:11:13
Called .then on  Promise { <state>: "rejected", <reason>: "Using Promise.reject" }  with arguments:  Array [ function (), function () ]  a.htm:11:13
Called .then on  Promise { <state>: "pending" }  with arguments:  Array [ function (), function () ]  a.htm:11:13
Caught: Using Promise.reject  a.htm:26:53
uncaught exception: Using Promise.reject     (unknown) 
FF59:

Code: Select all

Called .catch on  Promise { <state>: "pending" }  with arguments:  Array [ function () ]                  a.htm:15:5
Called .then on  Promise { <state>: "pending" }  with arguments:  Array [ undefined, function () ]  a.htm:11:5
Called .then on  Promise { <state>: "rejected", <reason>: "Using Promise.reject" }  with arguments:  Array [ function (), function () ]  a.htm:11:5
Called .then on  Promise { <state>: "pending" }  with arguments:  Array [ function (), function () ]  a.htm:11:5
Caught: Using Promise.reject    a.htm:26:45
uncaught exception: Using Promise.reject  (unknown)
FF60-68:

Code: Select all

Called .catch on  Promise { <state>: "pending" }  with arguments:  Array [ () ]  a.htm:15:13
Called .then on  Promise { <state>: "pending" }   with arguments:  Array [ undefined, () ] a.htm:11:13
Called .then on  Promise { <state>: "rejected" }  with arguments:  Array [ (), () ] a.htm:11:13
Called .then on  Promise { <state>: "pending" }   with arguments:  Array [ (), () ] a.htm:11:13
Caught: Using Promise.reject   a.htm:26:53
FF69:

Code: Select all

Called .catch on  Promise { <state>: "pending" }   with arguments:  Array [ () ]  a.htm:15:13
Called .then on   Promise { <state>: "pending" }   with arguments:  Array [ undefined, () ] a.htm:11:13
Called .then on  Promise { <state>: "rejected" }   with arguments:  Array [ (), () ] a.htm:11:13
Caught: Using Promise.reject   a.htm:26:53
MS Edge:

Code: Select all

Called .catch on Promise {<pending>} with arguments: [ƒ]  a.htm:15
Called .then on Promise {<pending>} with arguments: (2) [undefined, ƒ]  a.htm:11
Called .then on Promise {<rejected>: 'Using Promise.reject'} with arguments: (2) [ƒ, ƒ] a.htm:11
Caught: Using Promise.reject    a.htm:26

SemiKebab
Moonbather
Moonbather
Posts: 50
Joined: 2021-05-30, 03:48

Re: Unexpected "uncaught exception" using async functions

Unread post by SemiKebab » 2024-01-05, 09:42

Thanks Kris_88 for this back-to-back testing. :thumbup:

On a related note, while having a look at the bug tracker, I noticed the recent #2435 - Implement PromiseRejectionEvent, which might be involved in the same components.

User avatar
Kris_88
Keeps coming back
Keeps coming back
Posts: 940
Joined: 2021-01-26, 11:18

Re: Unexpected "uncaught exception" using async functions

Unread post by Kris_88 » 2024-01-05, 10:04

SemiKebab wrote:
2024-01-05, 09:42
On a related note, while having a look at the bug tracker, I noticed the recent
Yes, I saw that too. But perhaps there is some difference in the implementation of await and async functions, rather than in promises. The impression is that an extra promise is being created there.
And Moonchild didn't say anything...

User avatar
Moonchild
Pale Moon guru
Pale Moon guru
Posts: 35651
Joined: 2011-08-28, 17:27
Location: Motala, SE

Re: Unexpected "uncaught exception" using async functions

Unread post by Moonchild » 2024-01-05, 12:28

Kris_88 wrote:
2024-01-05, 10:04
And Moonchild didn't say anything...
I didn't say anything because I'd have to dive deep into the specs and various implementations to analyse the differences which i simply haven't had time for. Sorry to disappoint if you expected me to weigh in right away.
"Sometimes, the best way to get what you want is to be a good person." -- Louis Rossmann
"Seek wisdom, not knowledge. Knowledge is of the past; wisdom is of the future." -- Native American proverb
"Linux makes everything difficult." -- Lyceus Anubite

User avatar
Moonchild
Pale Moon guru
Pale Moon guru
Posts: 35651
Joined: 2011-08-28, 17:27
Location: Motala, SE

Re: Unexpected "uncaught exception" using async functions

Unread post by Moonchild » 2024-01-05, 14:19

FTR running your snippet on the branch post-implementation of the promise/microtask changes martok's been working on gives the following result:

Code: Select all

Called .catch on  Promise { <state>: "pending" }  with arguments:  Array [ function () ]  test.html:16:13
Called .then on  Promise { <state>: "pending" }  with arguments:  Array [ undefined, function () ]  test.html:12:13
Called .then on  Promise { <state>: "rejected", <reason>: "Using Promise.reject" }  with arguments:  Array [ function (), function () ]  test.html:12:13
Called .then on  Promise { <state>: "pending" }  with arguments:  Array [ function (), function () ]  test.html:12:13
Caught: Using Promise.reject  test.html:27:53
"Sometimes, the best way to get what you want is to be a good person." -- Louis Rossmann
"Seek wisdom, not knowledge. Knowledge is of the past; wisdom is of the future." -- Native American proverb
"Linux makes everything difficult." -- Lyceus Anubite

User avatar
Kris_88
Keeps coming back
Keeps coming back
Posts: 940
Joined: 2021-01-26, 11:18

Re: Unexpected "uncaught exception" using async functions

Unread post by Kris_88 » 2024-01-06, 04:12

OK.

Thank you!

SemiKebab
Moonbather
Moonbather
Posts: 50
Joined: 2021-05-30, 03:48

Re: Unexpected "uncaught exception" using async functions

Unread post by SemiKebab » 2024-01-31, 04:18

I have just tried the above snippets on the newly released Pale Moon 33, and the issue seems to be fixed. No exception thrown, as expected. Good work!