[javascript] Angular 1.6.0: "Possibly unhandled rejection" error

We have a pattern for resolving promises in our Angular app that has served us well up until Angular 1.6.0:

    resource.get().$promise
        .then(function (response) {
        // do something with the response
        }, function (error) {
            // pass the error the the error service
            return errorService.handleError(error);
        });

And here is how we are triggering the error in Karma:

    resourceMock.get = function () {
        var deferred = $q.defer();
        deferred.reject(error);
        return { $promise: deferred.promise };
    };

Now, with the update to 1.6.0, Angular is suddenly complaining in our unit tests (in Karma) for rejected promises with a "Possibly unhandled rejection" error. But we are handling the rejection in the second function that calls our error service.

What exactly is Angular looking for here? How does it want us to "handle" the rejection?

The answer is


To avoid having to type additional .catch(function () {}) in your code in multiple places, you could add a decorator to the $exceptionHandler.

This is a more verbose option than the others but you only have to make the change in one place.

angular
    .module('app')
    .config(configDecorators);

configDecorators.$inject = ["$provide"];
function configDecorators($provide) {

    $provide.decorator("$exceptionHandler", exceptionHandler);

    exceptionHandler.$inject = ['$delegate', '$injector'];
    function exceptionHandler($delegate, $injector) {
        return function (exception, cause) {

            if ((exception.toString().toLowerCase()).includes("Possibly unhandled rejection".toLowerCase())) {
                console.log(exception); /* optional to log the "Possibly unhandled rejection" */
                return;
            }
            $delegate(exception, cause);
        };
    }
};

Found the issue by rolling back to Angular 1.5.9 and rerunning the test. It was a simple injection issue but Angular 1.6.0 superseded this by throwing the "Possibly Unhandled Rejection" error instead, obfuscating the actual error.


You could mask the problem by turning off errorOnUnhandledRejections, but the error says you're needing to "handle a possible rejection" so you just need to add a catch to your promise.

resource.get().$promise
    .then(function (response) {
    // do something with the response
    }).catch(function (error)) {
        // pass the error to the error service
        return errorService.handleError(error);
    });

Reference: https://github.com/angular-ui/ui-router/issues/2889


Please check the answer here:

Possibly unhandled rejection in Angular 1.6

This has been fixed with 316f60f and the fix is included in the v1.6.1 release.


I have observed the same behavior during test execution. It is strange that on production code works fine and fails only on tests.

Easy solution to make your tests happy is to add catch(angular.noop) to your promise mock. In case of example above it should looks like this:

_x000D_
_x000D_
resourceMock.get = function () {_x000D_
    var deferred = $q.defer();_x000D_
    deferred.reject(error);_x000D_
    return { $promise: deferred.promise.catch(angular.noop) };_x000D_
};
_x000D_
_x000D_
_x000D_


The first option is simply to hide an error with disabling it by configuring errorOnUnhandledRejections in $qProvider configuration as suggested Cengkuru Michael

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(fn) method:

resource.get().$promise
    .then(function (response) {})
    .catch(function (err) {});

LINKS:


I was also facing the same issue after updating to Angular 1.6.7 but when I looked into the code, error was thrown for $interval.cancel(interval); for my case

My issue got resolved once I updated angular-mocks to latest version(1.7.0).


The code you show will handle a rejection that occurs before the call to .then. In such situation, the 2nd callback you pass to .then will be called, and the rejection will be handled.

However, when the promise on which you call .then is successful, it calls the 1st callback. If this callback throws an exception or returns a rejected promise, this resulting rejection will not be handled, because the 2nd callback does not handle rejections in cause by the 1st. This is just how promise implementations compliant with the Promises/A+ specification work, and Angular promises are compliant.

You can illustrate this with the following code:

function handle(p) {
    p.then(
        () => {
            // This is never caught.
            throw new Error("bar");
        },
        (err) => {
            console.log("rejected with", err);
        });
}

handle(Promise.resolve(1));
// We do catch this rejection.
handle(Promise.reject(new Error("foo")));

If you run it in Node, which also conforms to Promises/A+, you get:

rejected with Error: foo
    at Object.<anonymous> (/tmp/t10/test.js:12:23)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:394:7)
    at startup (bootstrap_node.js:149:9)
    at bootstrap_node.js:509:3
(node:17426) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: bar

It may not be your speficic situation, but I had a similar problem.

In my case, I was using angular-i18n, and getting the locale dictionary asynchronously. The problem was that the json file it was getting was incorrectly indented (mixing spaces and tabs). The GET request didn't failed.

Correcting the indentation solved the problem.


I had this same notice appear after making some changes. It turned out to be because I had changed between a single $http request to multiple requests using angularjs $q service.

I hadn't wrapped them in an array. e.g.

$q.all(request1, request2).then(...) 

rather than

$q.all([request1, request2]).then(...)

I hope this might save somebody some time.


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to angularjs

AngularJs directive not updating another directive's scope ERROR in Cannot find module 'node-sass' CORS: credentials mode is 'include' CORS error :Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response WebSocket connection failed: Error during WebSocket handshake: Unexpected response code: 400 Print Html template in Angular 2 (ng-print in Angular 2) $http.get(...).success is not a function Angular 1.6.0: "Possibly unhandled rejection" error Find object by its property in array of objects with AngularJS way Error: Cannot invoke an expression whose type lacks a call signature

Examples related to karma-runner

Angular 1.6.0: "Possibly unhandled rejection" error Karma: Running a single test file from command line npm check and update package if needed

Examples related to angular-promise

Angular 1.6.0: "Possibly unhandled rejection" error What is the difference between Promises and Observables? How to access the value of a promise? How to return a resolved promise from an AngularJS Service using $q? Wait for all promises to resolve Error handling in AngularJS http get then construct AngularJS : Initialize service with asynchronous data How to cancel an $http request in AngularJS?

Examples related to angularjs-1.6

Angular 1.6.0: "Possibly unhandled rejection" error