Skip to content
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

Promises with both .then and passed to .all always throw Unhandled rejection Error #493

Closed
tmoc opened this issue Feb 11, 2015 · 10 comments
Closed

Comments

@tmoc
Copy link

tmoc commented Feb 11, 2015

I've had this issue for a while and just spent the past day and a half trying to figure out the source of the problem. I've finally narrowed it down.

The following code results in an Unhandled rejection Error:

var promise1 = function () {
  return Promise.reject();
};

promise1()
.then(function () {
  console.log('great success');
});

Promise.all([promise1])
.catch(function (err) {
  console.log('handled the error');
});

Is this intended behavior?

@petkaantonov
Copy link
Owner

Yes it is intended behavior, not handling errors is a bug in the application and that's what you are being made aware of. To handle a rejected promise, you can use a catch handler:

promise1()
.then(function () {
  console.log('great success');
})
.catch(function(e) {
  console.log("handled the error");
});
promise1()
.then(function () {
  console.log('great success');
})
.catch(function(e) {
  console.log("handled the error");
});

promise1()
.then(function () {
  console.log('great success2');
})
.catch(function(e) {
  console.log("handled the error");
});

promise1()
.catch(function (err) {
  console.log('handled the error');
});

@petkaantonov
Copy link
Owner

Also don't reject with no argument (as that's the same as rejecting with undefined) this is equal to saying throw null in Java or something.

@threehams
Copy link

To add on to this explanation a bit (Petka, correct any of this if it's wrong):

var promise1 = function () {
  return Promise.reject();
};

promise1()
.then(function () {
  console.log('great success');
});

Promise.all([promise1])
.catch(function (err) {
  console.log('handled the error');
});

Here's what's actually happening here:

  1. You define promise1, and have it return a rejected promise when called.
  2. In the second statement, you call promise1(), which returns the rejected promise immediately (although the handling is asynchronous).
  3. Since the handling is async, you call Promise.all with an array of functions. Because the function isn't being called (i.e. [promise1()], no promise is returned, and per Promises/A+, this is interpreted as a value. Even if you comment out the second block, you won't reach the catch function.
  4. The .then function sees a rejection and propagates it until it crashes the process since there's no handler available.

Here's code that does what you're looking for:

var promise1 = function () {
  return Promise.reject('uh oh'); // or, throw new Error('uh oh') - gives a callstack
};

Promise.all([promise1().then(function() {
  console.log('great success');
})]).catch(function (err) {
  console.log('handled the error');
});

This puts the .then() within the chain containing .catch().
The structure of this is a bit strange, but it's a simple example - normally, the .then logic would be inside promise1().

@tmoc
Copy link
Author

tmoc commented Feb 12, 2015

This cleared a lot up for me, thanks.

@wmertens
Copy link

Hmm so that is why promise.should.be.rejected still throws? (using shouldjs/should-promise).

Any way to fix that? It's nicer to write the above instead of promise.then(throwerFn, acceptorFn)

@dmansfield
Copy link

I seem to be hitting this, too. It would seem that Promise.all is "handling" the rejection, but clearly it's not. I guess that could be documented?

@cfv1984
Copy link

cfv1984 commented May 11, 2017

I am seeing this error with the following structure:

new Promise((accept, reject) =>reject("test"))
  .then(
         () => console.log("ok"), 
         () => console.log('err')
  )
  .catch(
    (...args) => console.log("wtf", args)
  )

And I am not seeing this behavior on native Chrome or Firefox promises. What can be going on in here?

@PinkyJie
Copy link

same issue as @cfv1984

@nabilfreeman
Copy link

I'm using async/await and definitely catching my exceptions, but I still get this error.

@danielesegato
Copy link

danielesegato commented Oct 12, 2017

Sorry to wake up an old thread, I've this weird issue with jasmine testing framework and bluebird: it sometimes (not consistently) produce errors in the console log like this one:

Unhandled rejection Error: dummy
    at UserContext.<anonymous> (/home/mastro/ws/my-project-path/spec/unit/logic.spec.js:246:89)
    at UserContext.arguments.(anonymous function) (/home/mastro/ws/my-project-path/node_modules/jasmine-promises/dist/jasmine-promises.js:35:30)
    at attempt (/home/mastro/ws/platform/nsp-gamification-loyalty-services/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:4297:26)
    at QueueRunner.run (/home/mastro/ws/platform/nsp-gamification-loyalty-services/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:4217:20)
    at Timeout.runNext [as _onTimeout] (/home/mastro/ws/platform/nsp-gamification-loyalty-services/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:4257:20)
    at tryOnTimeout (timers.js:228:11)
    at Timer.listOnTimeout (timers.js:202:5)

Those are actually printed in the logs but do not make the test fail. In fact the test succeed, a test exhibiting the issue may look something like this:

        it('should throw if the check of `type` and `config` throws', () => {
            spyOn(actionHandler, 'validateActionConfig').and.returnValue(Promise.reject(new Error('dummy'))); 
            return sut.createAction(principal, action)
                .then(() => {
                    fail('Promise rejection expected, instead fulfilled');
                })
                .catch((err) => {
                    expect(actionHandler.validateActionConfig).toHaveBeenCalled();
                    expect(err.message).toBe('dummy');
                });
        });

The spyOn is jasmine way of testing mocked dependencies. sut is the subject under test. This test check our function createAction forward any rejectiong error from the call to actionHandler.validateActionConfig() by returning a rejection promise when the function is called.
That promise is then catched, as you can see, and we also check the error is exactly the one throw there. So the promise IS catched, but somehow it is detected as uncatched.

Furthermore this is not an on/off problem. Some test randomly exhibit this behavior, some never do.

I'm not sure if the issue here is on the jasmine or bluebird side. (I also posted this here jasmine/jasmine-npm#124)
Can you shed some light on what's possibly going on?
Thanks!

related dependencies

├── bluebird@3.5.1
│
├─┬ jasmine@2.8.0
│ └── exit@0.1.2
├── jasmine-core@2.8.0
├─┬ jasmine-expect@3.7.1
│ └── add-matchers@0.5.0
├── jasmine-promises@0.4.1
├─┬ jasmine-spec-reporter@3.3.0
│ └── colors@1.1.2

tmvumbi2 added a commit to jembi/md-form-builder that referenced this issue Oct 23, 2017
Note: removing the entire catch bloc causes an 'Uncaught (in promise)' error to be thrown in the console (even if the error is handled further up in Promise.all().catch; see: petkaantonov/bluebird#493 ).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants