Possibly unhandled rejection in Angular 1.6

55,555

Solution 1

This has been fixed with fix($q): Add traceback to unhandled promise rejections -- Commit 316f60f and the fix is included in the v1.6.1 release.

Solution 2

First option simply is to hide this specific rejection error by setting errorOnUnhandledRejections in $qProvider configuration as suggested Cengkuru Michael:

app.config(['$qProvider', function ($qProvider) {
    $qProvider.errorOnUnhandledRejections(false);
}]);

BUT this will only switch off logging. The error itself will remain

The better solution in this case will be - handling a rejection with .catch() method:

service.doSomething()
    .then(function (response) {})
    .catch(function (err) {});

Useful Links:

Solution 3

This information helped me to track down what (in my case) was creating the promise and not adding an error handler. I found it buried in the discussion of issue #2889 "Possibly unhandled rejection with Angular 1.5.9".

The gist, is, patch $q to cache a stack-trace on creating promises, such that it can be retrieved when the error is triggered.

To do it, insert this code to decorate $q somewhere near the top of your angular app:

// Decorate the $q service when app starts
app.decorator('$q', ["$delegate", function($delegate) {
  // Create a new promise object
  var promise = $delegate.when();

  // Access the `Promise` prototype (nonstandard, but works in Chrome)
  var proto = promise.__proto__;

  // Define a setter for `$$state` that creates a stacktrace 
  // (string) and assigns it as a property of the internal `$$state` object.
  Object.defineProperty(proto, '$$state', {
    enumerable: true,
    set: function(val) {
      val.stack = new Error().stack;
      this._$$state = val;
    },
    get: function() {
      return this._$$state;
    }
  });

  return $delegate;
}]);

Then search the angular code for the message "possibly unhandled rejection" and put a breakpoint on that line. When the breakpoint is reached, print out the value of toCheck.stack on the console, and you'll see something like this:

>> toCheck.stack
"set@http://localhost:8000/js/dual-site.js:18:19
Promise@http://localhost:8000/js/angular.js:17008:22
then@http://localhost:8000/js/angular.js:17016:20
catch@http://localhost:8000/js/angular.js:17026:14
SyncStrategy.prototype.send@http://localhost:8000/js/angular-state-machine.js:436:24
StateMachine/this.send@http://localhost:8000/js/angular-state-machine.js:235:16

The offending code is the frame calling angular's catch/then functions.

Solution 4

I fixed the same problem with version 1.6.1 by upgrading angular-ui-router to 0.3.2.

Solution 5

There is another case, adding a finally() handler to a promise generate the error: http://plnkr.co/edit/eT834BkIEooAMvrVcLDe

Because finally() creates a new promise and call the resolver on it. (Rejecting a 2nd one in a rejection case)

Ive put a fix in the plnkr but it doesn't look very good.

Share:
55,555
Piotr Pradzynski
Author by

Piotr Pradzynski

software developer @ prondzyn.com blogger @ ProgramistaNaSwoim.pl Toruń JUG co-founder and former co-leader Toruń JUG Day originator and coordinator @prondzyn on Twitter

Updated on August 14, 2020

Comments

  • Piotr Pradzynski
    Piotr Pradzynski almost 4 years

    I have a code with AngularJS:

    service.doSomething()
      .then(function(result) {
          //do something with the result
      });
    

    In AngularJS 1.5.9 when I have error in the .then() section like:

    service.doSomething()
      .then(function(result) {
          var x = null;
          var y = x.y;
          //do something with the result
      });
    

    I'm getting clear error message:

    TypeError: Cannot read property 'y' of null

    But in version 1.6 with the same code I'm getting a different error:

    Possibly unhandled rejection: {} undefined

    I know that this is related to this change, and the single solution is quite simple by adding .catch() block:

    service.doSomething()
      .then(function(result) {
          var x = null;
          var y = x.y;
          //do something with the result
      })
      .catch(console.error);
    

    Now I again have what I want:

    TypeError: Cannot read property 'y' of null

    But how to obtain the same result (more detailed error) for entire application without adding .catch() block in every single place?

    I tested the suggested solution to disable this by adding:

    $qProvider.errorOnUnhandledRejections(false);
    

    But with this the situation is even worse - I do not have ANYTHING in the console! The error is swallowed somewhere and not logged at all. I'm not sure is it a problem with AngularJS 1.6 or with my configuration.

    Do you have any ideas how to "restore" logging behavior from version 1.5.9?

    EDIT:

    Adding custom error handler:

    .factory('$exceptionHandler', function($log) {
      return function(exception, cause) {
        $log.warn(exception, cause);
      };
    })
    

    does not help at all. In the error handler I already receive the "wrapped" error.

  • Sharondio
    Sharondio over 7 years
    Discussion on this also buried in an old, unrelated issue: github.com/angular/angular.js/issues/14631
  • httpete
    httpete over 7 years
    In 1.6.1, I was still getting this error, using ngResource and $promise, so I had to use: $qProvider.errorOnUnhandledRejections(false);
  • gkalpak
    gkalpak over 7 years
    @httpete: OP asked how to get a more clear error, not how to suppress unhandled rejections (which is not a good idea imo).
  • Rouche
    Rouche over 7 years
    Well, i am with 1.6.1 and i still get the error. Even if i do have an error callback. Problem is my callback need to return a rejected promise so the client knows the service have an error. Then Poof! $http(config).then( (response) => {...}, (error) => { return $q.reject(error); } );
  • gkalpak
    gkalpak over 7 years
    If you don't handle a rejection, you get an error. That's how it works. (Note that each then() call returns a new promise.)
  • Rouche
    Rouche over 7 years
    Well, this means i have to do same thing as @httpete, or its a no go sadly :(. We have an interceptor wich deals with unhandled promises so that we dont need to do the same code everywhere.
  • Piotr Pradzynski
    Piotr Pradzynski over 7 years
    It is not good solution. I tested it and in some situations this setting will hide the true error as well.
  • Spock
    Spock over 7 years
    0.4 fixes some bugs also.
  • Admin
    Admin over 6 years
    This should be the right answer, and this should be part of Angular. Thanks a lot!!
  • Mawg says reinstate Monica
    Mawg says reinstate Monica about 4 years
    I get this error when moving from 1.5 to 1.7, and I do not have any (explicit) promises in my code. It functions perfectly in 1.5, but throws that error 3 times on starting in 1.7