-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
returning Promise.reject in async function results in Unhandled rejection error message #1404
Comments
I believe I'm encountering another instance of this issue. In fact I was going to post a new issue before I saw this one. Here's my description: This issue is a bit difficult to grasp, so I'll do my best to explain with examples. It seems that when using These code snippets are runnable directly on node 8 (tested on v8.1.0) with Bluebird v3.5.0 (and earlier). First, let's start from a problematic example. // Failing example 1
const Promise = require('bluebird')
Promise.using(Promise.resolve(), async () => {
await Promise.reject(new Error('foo'))
})
.catch(() => console.log('OK')) This snippet, when run, produces the following output:
As you can see, we have an unhandled rejection error yet we did handle the error, and no clear way of rewriting the snippet so that the unhandled rejection would not occur. Confusingly, if we reject by using native promises, we do not get the unhandled rejection. In this snippet, we only use // Working example 1
const Bluebird = require('bluebird')
Bluebird.using(Promise.resolve(), async () => {
await Promise.reject(new Error('foo'))
})
.catch(() => console.log('OK')) This outputs simply:
Similarly, this also prints the warning: // Failing example 2
const Promise = require('bluebird')
const reject = () => Promise.reject(new Error('foo'))
Promise.using(Promise.resolve(), async () => {
await reject()
})
.catch(() => console.log('OK'))
However, this one doesn't: // Working example 2
const Bluebird = require('bluebird')
const reject = () => Promise.reject(new Error('foo'))
Bluebird.using(Promise.resolve(), async () => {
await reject()
})
.catch(() => console.log('OK'))
And neither does this one: // Working example 3
const Promise = require('bluebird')
const reject = async () => {
throw new Error('foo')
}
Promise.using(Promise.resolve(), async () => {
await reject()
})
.catch(() => console.log('OK'))
With async/await translated to plain promises, the failing examples also work without issue: // Previously failing example 1 (working w/o async)
const Promise = require('bluebird')
Promise.using(Promise.resolve(), () => {
return Promise.reject(new Error('foo'))
})
.catch(() => console.log('OK'))
// Previously failing example 2 (working w/o async)
const Promise = require('bluebird')
const reject = () => Promise.reject(new Error('foo'))
Promise.using(Promise.resolve(), reject)
.catch(() => console.log('OK'))
This leads me to believe that there may perhaps be a bug in Bluebird, causing a rejected bluebird-promise returned by an async function to be handled asynchronously. Thoughts? |
I'm encountering this in my async express middleware when an Using native promises in Node does not cause this problem. Now that Node supports async/await natively, more and more people will start to use it and they will probably run into this issue as well. |
as @medikoo says #1411 (comment)
so it looks like rejected bluebird |
@zowers is that also the case when your app overwrites it in the global space, e.g. |
@adamreisnz I believe there's no way to alter the type of Promise returned from async functions, it is always internal const SavePromise = global.Promise;
global.Promise = String;
async function f1() {
return "ok"
}
const p = f1();
console.log( "f1 returned: ", p );
console.log( "p instanceof global.Promise: ", p instanceof global.Promise );
console.log( "p instanceof SavePromise: ", p instanceof SavePromise );
|
Currently "solving" this by ignoring unhandled rejections altogether, but really hoping for a proper fix soon; Promise.onPossiblyUnhandledRejection = function() {}; |
We just got bit by this issue. We've just recently moved to node@8.2.1 and are using async/await extensively, along with bluebird. I see @suguru03 has a PR to fix it, is that going to be merged soon? |
Any movement on this issue and the PR? |
The await mechanism simply isn't internally calling .then on the promise soon enough. It has inaccessible microtask queue that runs later than the microtask queue bluebird is using and because no .then is called by the time bluebird's microtask queue is flushed, unhandled rejection is generated. |
We can just wait a macrotask? |
Yeah seems so. Changing this to setTimeout should do it |
Awesome, thanks for the fix 🎉 |
I'm still seeing this on 3.5.1 in a hapi service I'm developing - unhandled rejection with bluebird, caught ok with native promises. I tried creating a simple example to repro the problem, but of course that worked fine. Could the setTimeout fire before that inaccessible microtask queue? I'll try to create an example more like my actual code to give you. |
Actually it can very rarely fire an additional timer before a tick IIRC, can you try and reproduce? |
Adding the setTimeout here seems to have broken a number of unit tests for us that use fake timers. |
This change causes resource leak check to fail in our tests |
@AntonBazhal can you elaborate on the topic? |
@andrewaustin I fixed that from lolex's end (fake timers), are you still seeing the issue? |
@benjamingr We use lambda-tester for testing our serverless applications (AWS Lambda). It does resource leak check with lambda-leak. Basically, it takes active handles before and after the test and compares them. This timer pops up during the comparison and is considered a potential resource leak since execution is already complete, but timer is still active. |
Sounds like a bug should be filed against that library then. I'm unable to reproduce the issue. |
Library does not expect any timers to hang around after execution is complete, which looks reasonable to me. Our tests fail not every time, rather in a random manner. Probably it depends on whether this timer event happens before or after the execution is done. |
What version of bluebird is the issue happening on?
3.5.0
What platform and version? (For example Node.js 0.12 or Google Chrome 32)
Node.js 8.0.0 on Ubuntu
Did this issue happen with earlier version of bluebird?
Yes
When returning Promise.reject in async function, an error is printed on the console "Unhandled rejection" even the promise is caught. It doesn't print out the error if native Promise is used.
The text was updated successfully, but these errors were encountered: