in release 3.23.2, the new feature "Sensible non-Error exception serializer" (#1253) causing errors which are made with es6-error
(https://www.npmjs.com/package/es6-error) to change the error content.
it is being change in captureException
function in this line:
options = this._getCaptureExceptionOptionsFromPlainObject(options, ex);
to be more specific, here is my code:
import ExtendableError from 'es6-error'
class CustomError extends ExtendableError {
constructor(code, message) {
super(message)
this.name ='CustomError'
this.code = code
}
}
export default CustomError
then in the code:
Raven.captureException(new CustomError('code123', 'not working'));
// this will cause the error message to be "Non-Error exception captured with keys: code"
That seems to be a very strange behavior of JS modules.
When you use:
import ExtendableError from 'es6-error'
class CustomError extends ExtendableError {
constructor(code, message) {
super(message)
this.name ='CustomError'
this.code = code
}
}
function isPlainObject(what) {
return Object.prototype.toString.call(what) === '[object Object]';
}
function isError(value) {
switch ({}.toString.call(value)) {
case '[object Error]':
return true;
case '[object Exception]':
return true;
case '[object DOMException]':
return true;
default:
return value instanceof Error;
}
}
function isErrorEvent(value) {
return Object.prototype.toString.call(value) === '[object ErrorEvent]';
}
var ex = new CustomError('code123', 'not working');
console.log('isPlainObject:', isPlainObject(ex))
console.log('isError:', isError(ex))
console.log('isErrorEvent:', isErrorEvent(ex))
It'll incorrectly report true/true/false
.
However, when you'll substitute import
statement with the code itself
class ExtendableError extends Error {
constructor(message = '') {
super(message);
// extending Error is weird and does not propagate `message`
Object.defineProperty(this, 'message', {
configurable: true,
enumerable : false,
value : message,
writable : true,
});
Object.defineProperty(this, 'name', {
configurable: true,
enumerable : false,
value : this.constructor.name,
writable : true,
});
if (Error.hasOwnProperty('captureStackTrace')) {
Error.captureStackTrace(this, this.constructor);
return;
}
Object.defineProperty(this, 'stack', {
configurable: true,
enumerable : false,
value : (new Error(message)).stack,
writable : true,
});
}
}
it'll correctly report false/true/false
.
I'll try to debug why it's the case and if I won't be able to find out, we'll just swap checks to go through isError
first.
@zivl When you test it locally, and create your own custom-error.js
file with that code and import it as a module, it works correctly.
The issue is that this library doesn't export it's code "as is", but precompiles it using Babel.
Sooo it ends up being "kinda" error but not really. It's a plain object that inherits specific properties and has a prototype
set to the Error
itself.
There's no way around this unfortunately other than changing check order, as it's like a "schrodinger error". It is and is not an Error at the same time.
@zivl released in 3.23.3
. Thanks for the report!
Most helpful comment
@zivl When you test it locally, and create your own
custom-error.js
file with that code and import it as a module, it works correctly.The issue is that this library doesn't export it's code "as is", but precompiles it using Babel.
Sooo it ends up being "kinda" error but not really. It's a plain object that inherits specific properties and has a
prototype
set to theError
itself.There's no way around this unfortunately other than changing check order, as it's like a "schrodinger error". It is and is not an Error at the same time.