sentry-react-native: Non-Error exception captured with keys: error

OS:

  • Windows
  • MacOS
  • Linux

Platform:

  • iOS
  • Android

Output of node -v && npm -v && npm ls --prod --depth=0

v9.7.1
5.7.1

Config:

Sentry.config('https://...@sentry.io/...', {
....
}).install()
"react": "16.2.0",
"react-native": "0.53.0",
"react-native-sentry": "^0.35.3",

I am getting lots of crashes with this error -

 } else if (isPlainObject(ex)) {
      // If it is plain Object, serialize it manually and extract options
      // This will allow us to group events based on top-level keys
      // which is much better than creating new group when any key/value change
      options = this._getCaptureExceptionOptionsFromPlainObject(options, ex);
      ex = new Error(options.message);
    } else {
      // If none of previous checks were valid, then it means that
      // it's not a plain Object
      // it's not a valid ErrorEvent (one with an error property)
      // it's not an Error

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 12
  • Comments: 44 (11 by maintainers)

Commits related to this issue

Most upvoted comments

This is not specific to react-native, i got this on angular 6 application

So, if this has occurred, it means that Sentry/Raven doesn’t believe the error is an Error but rather some other object. And we iterate through the keys to give you a clue what we caught instead.

Note that if you’re trying to capture a custom Error (e.g. a subclass, whether defined by your code or the framework code), there’s a specific way to do this to make sure it also is detectable as an Error. You can verify it works by verifying MyError instanceof Error evaluates to true.

For example, @jackrvaughan wrote:

Non-Error exception captured with keys: error, headers, message, name, ok…

This means that Sentry/Raven encountered a JavaScript object with this shape:

{
  error: { ... /* some genuine error object probably? */ ... },
  headers: { ... /* some sub-object probably? */ },
  message: '???',
  name: '???',
  ...
}

(That doesn’t look like an Error proper to me.)

Still got this error: Non-Error exception captured with keys: error, headers, message, name, ok…

@lilywang711 I would like to disagree, the error can be an Error, ErrorEvent or string. While only setting a string may work for you, it is not a solution for everybody.

Also still getting this for an angular6 frontend:

Non-Error exception captured with keys: error, headers, message, name, ok…

EDIT: Sorry - didn’t realize this was specific to react-native-sentry

@HazAT Here is a link for a similar error (“Error: Non-Error exception captured with keys: errorCode, errorMessage…”):

https://sentry.io/share/issue/1d9a134305c747f6a134880e134e51d5/

I would see that info in the console breadcrumbs?

No, we are excluding logging from our own callbacks, otherwise, it could create an infinite loop.

You can do something like:

Sentry.init({
  dsn: 'your_dsn',
  beforeSend(event, hint) {
    if (event.message.startsWith('Non-Error exception captured') && hint.originalException.error) {
      Sentry.withScope((scope) => {
        scope.setExtra('nonErrorException', true);
        Sentry.captureException(hint.originalException.error);
      });
      return null;
    }
    return event;
  }
})

This’ll prevent those errors from being sent to Sentry and will catch originalException.error instead. You can do any filtering/modifications in beforeSend or even better, an event processor. https://docs.sentry.io/platforms/javascript/#eventprocessors

@valerii-cognite then you have throw { message: '', status: '' } somewhere in your code, where the only thing you should throw is error instance

The next release (which is currently building) should fix this. Stay tuned for 0.36.0.

Hello, I have the same issue with an angular 6 app, my Raven-js version is 3.26.3 and my sentry version 9.0.0

@glebmachine Yep, agreed - just this issue is in the react-native-sentry repo

@Riccardo-Andreatta yeh, my example had a bug 😅 It should be scope.setExtra, not Sentry.setExtra. Regarding first error, it’s because we assume originalException is an Error object, but in case of this thread, it’s a non-standard one (there’s no Error.error in the native implementation).

interface ExtendedError extends Error {
  error: Error; // or `any`
}

and then

if (!hint.originalException) return event;

const customError = (hint.originalException as ExtendedError).error;

if (event.message.startsWith('Non-Error exception captured') && customError) {
  Sentry.withScope((scope) => {
    scope.setExtra('nonErrorException', true);
    Sentry.captureException(customError);
  });
  return null;
}

@richardshergold if you’re able to reproduce it locally, use

init({
  dsn: 'your_dsn',
  beforeSend(event, hint) {
    console.log(hint.originalException);
    return event;
  }
})

to investigate what’s the shape of the error and update it appropriately.

I tried this solution https://github.com/getsentry/sentry-javascript/issues/1260#issuecomment-373398920 but still getting something like:

errorNon-Error exception captured with keys: [object has no keys]

hey,I found the reason in my project,It doesn’t matter with the version or framwork. The correct format to throw the error is throw new Error(err.data.message), not throw new Error(err) Which means that the error should be a String

After I modified this, this error has never happened again. hope this helps

@DataGreed not sure what’s the status of react-native on this issue as I’m not working on it. However, new v1 uses @sentry/browser (this SDK) instead of old raven.js SDK, thus I assume it should be fixed – https://github.com/getsentry/sentry-react-native/releases

@cihati this is exactly what you should see, as we are trying to provide any usable information that can be used to find out where is the cause 😃

In this case, you somewhere do throw obj where obj is the thing from the log above.

react-native-sentry doesn’t have beforeSend with the hint, but setDataCallback instead as it’s not part of our core sentry-javascript SDK yet.

Sentry.setDataCallback((event) => {
  // you can inspect and override the event here as described in the comments above
  return event;
});

There’s no mechanism that passes original instance that was used to create a Sentry event. Only new v4 SDK has this feature. They are called hints https://docs.sentry.io/platforms/javascript/#hints Yes, it’s one of the reasons why some people move to the new version.