-
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
Warning: a promise was rejected with a non-error: [object Error] #990
Comments
Upd: To hot-fixing this issue. You can create another instance for Error and proxy all props from previous to new, and reject a promise with created Error.
However, bluebird should use [[Class]] prop to determine errors ( |
What about error subclasses? |
For subclasses - same. Checked with @benjamingr do you need a PR with failing test case? |
Let's be more concrete. Can you show me a piece of code that takes something and determines if it's an error? |
Sure. Consider following snippet: export async function evalInWindowAsync (win, func/*nodeClb, jQuery*/, additionalArgs = []) {
return new Promise((resolve, reject) => {
let args = [];
const argsId = _.uniqueId('evalInWindow_arg_holder_');
const callback = function(err, res) {
delete win[argsId];
if (err) {
const proxiedError = new EvalError();
proxiedError.message = err.message;
proxiedError.stack = err.stack;
reject(proxiedError);
} else {
resolve(res);
}
};
args.push(callback);
args = args.concat(additionalArgs);
win[argsId] = args;
const evalArgs = [`window["${argsId}"][0]`, `window.jQuery`];
for (var i = 1; i < args.length; i++) {
evalArgs.push(`window["${argsId}"]["${i}"]`);
}
const functionString = _.isString(func) ? functionString : func.toString();
const safeFunctionString = `function (done) {'use strict'; try { (${functionString}).apply(this, arguments); } catch (e) { done(e); } }`;
const evalString = `;(${safeFunctionString})(${evalArgs.join(',')});`;
win.eval(evalString);
});
} Code, which determines - resolve or reject a Promise. It's a Node-style callback. const callback = function(err, res) {
// ...
if (err) {
const proxiedError = new EvalError();
proxiedError.message = err.message;
proxiedError.stack = err.stack;
reject(proxiedError);
} else {
resolve(res);
}
}; And demo itself (snippet from a test case with chai-as-promised): const win = frame.contentWindow;
const stub = function (done, $) { throw new Error('an error'); }
return evalInWindowAsync(win, stub).should
.eventually.be.rejectedWith('an error');
|
[[Class]] Doesn't work with subclasses: function MyError() {
Error.apply(this, arguments);
Error.captureStackTrace(this, MyError);
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = Error;
var error = new MyError();
({}.toString.call(error)) //[Object object] |
@benjamingr I guess we could check for presence of .name, .message and .stack |
@petkaantonov almost forgot about that. Sorry for misinfo |
I'm also getting the "promise was rejected with a non-error" warning for regular It worked fine with Bluebird 2.9.x |
For anyone who finds this though hair pulling and Google. This bug is also relevant for cases in Node.js that use |
Checking if message and name are string (e77224c) causes a new bug since 'message' is actually optional. so now rejecting with simply "new MyError()" (my error extends Error..) doesn't work anymore (causes the "rejected with non error [object Error]" warning). I realize it is difficult to effectively check if an object is an error, so how about trying both the old way and the new: function isErrorLike(obj) {
return obj !== null &&
typeof obj === "object" &&
typeof obj.message === "string" &&
typeof obj.name === "string";
}
function canAttachTrace(obj) {
return (obj instanceof Error || isErrorLike(obj)) && es5.propertyIsWritable(obj, "stack");
} what do you think? |
@petkaantonov ^ sounds good to me generally. |
Even if you don't pass message, it's still the empty string. Maybe your transpiler doesn't do subclassing correctly? |
@petkaantonov subclass is often done like this: // Example for Node.js
const util = require('util');
function SubError (message) {
Error.captureStackTrace(this, this.constructor);
// Stuff
this.message = message;
}
util.inherits(SubError, Error);
var err = new SubError ();
console.log(typeof err.message); // => undefined Most people probably don't set a default value in such a case. |
That's not a subclass (it would not be |
So what if it's proprietary? Can we detect it? |
Can't we just check for .stack? |
I updated my example to inherit from Error. I implied a Node.js inheritance. |
You forgot to call super constructor, captureStackTrace doesnt do it and doesnt work in all browsers |
.stack is non standard so no |
.fail((xhr, err) => {
let proxy = new Error();
proxy.message = err || 'error is null';
proxy.name = 'ajax error';
reject(proxy);
}); |
Apologies for commenting on an old issue, but @BridgeAR's comment still holds for ES classes. Here's an example from Sequelize: class BaseError extends Error {
constructor(message) {
super(message);
this.name = 'SequelizeBaseError';
this.message = message;
Error.captureStackTrace(this, this.constructor);
}
} Now, why they have @petkaantonov Would you reconsider adding back the function isError(obj) {
return obj instanceof Error ||
(obj !== null &&
typeof obj === "object" &&
typeof obj.message === "string" &&
typeof obj.name === "string");
} Happy to open a PR. |
The way Sequelize instantiates some of its Error subclasses confuses Bluebird into thinking that Promises are rejected with non-Error objects. See petkaantonov/bluebird#990
@gabegorelick yeah should be no harm in it |
The way Sequelize instantiates some of its Error subclasses confuses Bluebird into thinking that Promises are rejected with non-Error objects. See petkaantonov/bluebird#990
I am experiencing this issue using aurelia-http-client. Even configure the client using a HttpInterceptor returning a new Error per errorCode case, I still see the warning un browser console. I am not able to remove this warning. |
@jalmansa88 well - for start you can turn it off directly, it's very unlikely we'll be able to help you without a MCVE |
Is there a way to turn off just this specific warning but not other warnings? |
Thanks @benjamingr |
The only warning suppression flag I see there is for when you forget to return a promise.
Maybe I am missing something? In any case, I only get the warning on startup when es6-shim tries to initialize and test the features supported by the Promise impl in the env. See https://github.com/paulmillr/es6-shim/blob/8583cbe2186ec12bfbf4218ccbce7fc73f96de87/es6-shim.js#L2654 I'll suppress this myself so no worries. Just wanted to know if there is a way to turn it off already. |
A warning is fired when I reject a Promise with an
new Error('...')
, but Promise and Error are from differentWindow
's (e.g. window.opener and window child - from window.open or iframe.contentWindow).Of cource, it means, that
rejectReason instanceof Error
returnsfalse
, because Error is instance of iframe.contentWindow.Error (not of window.Error)The text was updated successfully, but these errors were encountered: