Sentry-javascript: BUG: release 3.23.2 caused change of exception messages due to non-Error exception serialiser

Created on 15 Mar 2018  ·  3Comments  ·  Source: getsentry/sentry-javascript

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"

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 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.

All 3 comments

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!

Was this page helpful?
0 / 5 - 0 ratings