bluebird: Invalid `rejected with a non-error` warning

When we set a message in out custom error object based on some non-string data, Bluebird displays Warning: a promise was rejected with a non-error: [object Object], which is clearly a mistake.

Here’s complete example:

'use strict';

var util = require('util');
var promise = require('bluebird');

function CustomError(data) {
    this.message = data;
    Error.captureStackTrace(this, CustomError);
}

util.inherits(CustomError, Error);
CustomError.prototype.name = 'CustomError';

promise.reject(new CustomError([]))
    .catch(error=> {
        console.log(error);
    });

This should not produce that warning, but it does.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 27 (13 by maintainers)

Most upvoted comments

@vitaly-t Just don’t freeze the error. At the very least, leave the stack property writable, or don’t turn on longStackTraces.

By the way, I already wrote about this restriction yesterday, when you only quoted “No” from that text and LOLed. Last restriction was “the stack property needs to be writable”

https://github.com/petkaantonov/bluebird/issues/1146#issuecomment-228826885

This should definitely be in the docs, in some form.

Remove Object.freeze(e) from lib/ext/batch.js - bluebird expects that the stack property is writable when longStackTraces are on.

(You’ll probably need to do it for lib/ext/sequence.js too, where its repeated as Object.freeze(error))

To make it easier to debug this, the freezing concern that modifies the error object should have been a part of the error unit/submodule. That way unit tests will be able to catch this.

Not sure whats going on other than that, when you run this in normal code that doesn’t attempt to do so much wrapping of bluebird behaviour

Promise.resolve()
.then(function() {
  var e = new Error();
  Object.freeze(e);
  throw e;
}).catch(function(error) {
  console.log("Caught: ", error.stack);
});

you get a clearer error:

TypeError: Cannot redefine property: stack
    at Object.defineProperty (native)
    at Object.notEnumerableProp (/node_modules/bluebird/js/release/util.js:97:9)
    at CapturedTrace.attachExtraTrace (/node_modules/bluebird/js/release/debuggability.js:725:10)
    at Promise.longStackTracesAttachExtraTrace [as _attachExtraTrace] (/node_modules/bluebird/js/release/debuggability.js:379:19)
    at Promise._rejectCallback (/node_modules/bluebird/js/release/promise.js:466:10)
    at Promise._settlePromiseFromHandler (/node_modules/bluebird/js/release/promise.js:513:17)
    at Promise._settlePromise (/node_modules/bluebird/js/release/promise.js:561:18)
    at Promise._settlePromiseCtx (/node_modules/bluebird/js/release/promise.js:598:10)
    at Async._drainQueue (/node_modules/bluebird/js/release/async.js:143:12)
    at Async._drainQueues (/node_modules/bluebird/js/release/async.js:148:10)
    at Immediate.Async.drainQueues [as _onImmediate] (/node_modules/bluebird/js/release/async.js:17:14)
    at tryOnImmediate (timers.js:543:15)
    at processImmediate [as _immediateCallback] (timers.js:523:5)
function isError(obj) {
    return obj !== null &&
           typeof obj === "object" &&
           typeof obj.message === "string" &&
           typeof obj.name === "string";
}

Not exactly unexpected. This only happens when longStackTraces is on, in which case bluebird must modify the stack property to add to the stack trace. In normal situations you’ll get a clearer error, however when the above type error occurs, spex converts it again to a BatchError which fails to pass the isError test. I don’t know where that happens in spex.