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

Package + Version

  • @sentry/browser
  • @sentry/node
  • raven-js
  • raven-node (raven for node)
  • other:
  • @angular/core

Version:

5.7.1 (@sentry/browser)
8.2.11 (@angular/core)

Description

I have initial setup for Angular app with global ErrorInterceptor here how I send it

    const eventId = Sentry.captureException(error.originalError || error);
    Sentry.showReportDialog({ eventId });

and I get this (Non-Error exception captured with keys: error, headers, message, name, ok) error again and again, and can’t understand what is wrong from the description and how to reproduce it.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 6
  • Comments: 65 (23 by maintainers)

Commits related to this issue

Most upvoted comments

We are currently using the following to ignore it.

Sentry.init({
  ignoreErrors: [
    'Non-Error exception captured'
  ]
});

Closing the issue, as it seems like the original issue has been partially resolved or there is a working solution. I’d prefer someone to create a new issue with a fresh description if it’s still an issue. Please do not hesitate to ping me if it is still relevant, and I will happily reopen and work on it. Cheers!

I decided to do this

Sentry.init({
            dsn: environment.sentryUrl,
            beforeSend(event, hint) {
                /* tslint:disable:no-string-literal only-arrow-functions */
                const isNonErrorException =
                    event.exception.values[0].value.startsWith('Non-Error exception captured') ||
                    hint.originalException['message'].startsWith('Non-Error exception captured');
                /* tslint:enable:no-string-literal only-arrow-functions */

                if (isNonErrorException) {
                    // We want to ignore those kind of errors
                    return null;
                }
                return event;
            }
        });

Docs update and necessary JS SDK change are coming:

https://github.com/getsentry/sentry-docs/pull/1695/ https://github.com/getsentry/sentry-javascript/pull/2601

It should be released this week! 😃

This means that the object you provide is not an instance of Error which holds the stacktrace in Angular app.

You should (as the message points to) use Sentry.captureException(error.error) or Sentry.captureException(error.message) depending on your needs.

I used an https://github.com/gothinkster/angular-realworld-example-app app as an example, just so that everyone can also do the same reproduction.

Barebone cloned app, followed Sentry’s Angular docs and uploaded the sourcemaps. Here are the results.


Example 1: Broken logic

What Angular gives you in an error handler + what event we capture:

Screenshot 2020-04-16 at 12 01 13

How it looks in the UI:

Screenshot 2020-04-16 at 12 07 02

Note: Everything is in place, you can easily point to the correct line of code that was broken, error message and error type is correct, because Angular gives you a whole Error object to work with.


Example 2: Broken service call

What Angular gives you in an error handler + what event we capture:

Screenshot 2020-04-16 at 12 00 49

How it looks in the UI:

Screenshot 2020-04-16 at 12 07 12 Screenshot 2020-04-16 at 12 08 03

Note: There’s no way to tell what type of error has been thrown, because Angular doesn’t give you this information. However, you can take a look at serialized data to tell, that there was “404 Not Found” error, which most likely came from invalid XHR call. Then, you can investigate the breadcrumbs flow to see that in fact there was an XHR call to the given url (which in this case contained a typo), preceeded by a click on an exact DOM element, which triggered it. With this information, it should be enough in 99% cases to fix the issue.


We can only work with what we’ve been given by the framework. Otherwise, we’d have to monkey-patch the framework itself.

@kamilogorek still getting this error, even with this

    const exception = error.error || error.message || error.originalError || error;
    const eventId = Sentry.captureException(exception);

It has not been resolved. I just tried to integrate Sentry with Angular 8 and found this issue.

Just chiming in to say I am also getting these errors. I’m using Angular 8 and after reading quite a few issues on this, I realise that it might be a case of me not handling the error properly in my error handling component. I’ve tried the workarounds suggested by others defining the exception before being passed to captureException but this hasn’t reduced the errors. It’d be great if anyone could give some further input on this or I’ll just have to use GChronos’s (Thanks!) solution.

I don’t get it how can Sentry claim out of the box setup, it’s completely false.

Hi, I’ve spent some time on this issue and found that error.error.message on errors of type HttpErrorResponse does not necessarily contain any information. If we look at the constructor we’ll see that Angular sets the message prop on the root object and not on ErrorEvent.

https://github.com/angular/angular/blob/cb3db0d31b91bea14c7f567fe7e7220b9592c11b/packages/common/http/src/response.ts#L345

By changing this line https://github.com/getsentry/sentry-javascript/blob/8eb72865dcd62ff719441105c7eda28007a07e9d/packages/angular/src/errorhandler.ts#L112 to

if (error.error instanceof ErrorEvent && error.error.message)

the error handler proceeded to return error.message; and threw the expected error.

New docs and 5.16.0 just has been released - https://docs.sentry.io/platforms/javascript/angular/ I tried to make it as explicit and detailed as possible, and that’s why it “may look” like a lot of code.

We are currently using the following to ignore it.

Sentry.init({
  ignoreErrors: [
    'Non-Error exception captured'
  ]
});

Why isn’t this option documented anywhere?

Exactly, and besides I’m paying for Sentry to do the work for me. It’s not an open source project where I do expect to get my hands dirty.

I like Sentry but I could look for alternatives…

We can only work with what we’ve been given by the framework. Otherwise, we’d have to monkey-patch the framework itself.

Is this your way of saying “not our problem”? Before switching to sentry (from some competitors) these XHR errors were captured just fine and they used the same install method with an angular error handler.

@kamilogorek Truth to be told, that ain’t working with Angular since over 6 months, there’s enough of reports here to confirm it, thus IMO there’s no need for further repro cases, you can find it out by yrself pretty easily. I know myself it doesn’t, since we have the same issue in our project using Angular v8, and now v9 (no sourcemaps).

@kamilogorek I believe you can init a new Angular 8 project, and make a http request towards a endpoint returning 500 and not catch the error in the http service so it propagates to Sentry.

Great catch @jakkn, thanks! Updated handler in the PR https://github.com/getsentry/sentry-javascript/pull/2903

@kamilogorek thx you are the best. Wrote my own error extractor. That solves the problem Didnt know that there could be so much different stuff in an HttpErrorResponse…

ignoreErrors: ['Non-Error exception captured'] is now missing from this tips page above?

const exception = error.error || error.message || error.originalError || error;

this will evaluate to true/false

I hit this same error, although it was for the express request handler and not angular. Basically I was calling next with a pojo instead of an Error object. I do some fun things in my own express error handler to turn it into something of interest, but because the sentryio request middleware goes first, it didn’t get this marshalled error.

In the end, created a utility function that would turn whatever was provided into something more reasonable:

export const handleMaybeError = err => {
  if (err instanceof Error) return err
  const newErr = new Error(err.message || 'unexpected')
  for (const [key, value] of Object.entries(err)) {
    newErr[key] = value
  }
  return newErr
}

export const someController = (req, res, next) => {
  try {
    await handleResponse(req, res)
  } catch (err) {
    next(handleMaybeError(err))
  }
}

This muxes up the stack traces I think, but really if it was a pojo passed into this, there was no stack trace anyway.

In our instance, before this was fixed, the vast majority of events reported were for this particular issue and because it’s a long-running node web server, breadcrumbs are near useless – and all the errors get lumped into this one event type.

Using Angular 8 and had the same issue Non-Error exception. Modified the example ‘extractError’ code as follows:

private static extractError(error: any) {
    // Try to unwrap zone.js error.
    // https://github.com/angular/angular/blob/master/packages/core/src/util/errors.ts
    if (error && error.ngOriginalError) {
      error = error.ngOriginalError;
    }
    // We can handle messages and Error objects directly.
    if (typeof error === 'string' || error instanceof Error) {
      return error;
    }
    // If it's http module error, extract as much information from it as we can.
    if (error instanceof HttpErrorResponse) {
      // The `error` property of http exception can be either an `Error` object, which we can use directly...
      if (error.error instanceof Error) {
        return error.error;
      }
      // ... or an`ErrorEvent`, which can provide us with the message but no stack...
      if (error.error instanceof ErrorEvent) {
        return error.error.message;
      }
      // ...or the request body itself, which we can use as a message instead.
      if (typeof error.error === 'string') {
        return `Server returned code ${error.status} with body "${error.error}"`;
      }
      // If we don't have any detailed information, fallback to the request message itself.
      return error.message;
    }

    // ***** CUSTOM *****
    // The above code doesn't always work since 'instanceof' relies on the object being created with the 'new' keyword
    if (error.error && error.error.message) {
      return error.error.message;
    }
    if (error.message) {
      return error.message;
    }
    // ***** END CUSTOM *****

    // Skip if there's no error, and let user decide what to do with it.
    return null;
  }

Modified my Sentry.init beforeSend based on @untilinvite’s beforeSend example above. This change is to handle a second log message from https://github.com/getsentry/sentry-javascript/issues/2169 also resolving as a Non-Error.

 Sentry.init({
        dsn: AppConfig.envSettings.sentryDSN,
        maxBreadcrumbs: 50,
        environment: this.getEnvName(),
        integrations: [new Sentry.Integrations.Breadcrumbs({ console: false })],
        beforeSend(event, hint) {
          // Note: issue with double entries during http exceptions: https://github.com/getsentry/sentry-javascript/issues/2169
          // Note: issue with a second entry not being set correctly (as a non-error): https://github.com/getsentry/sentry-javascript/issues/2292#issuecomment-554932519
          const isNonErrorException = event.exception.values[0].value.startsWith('Non-Error exception captured');
          if (isNonErrorException) {
            if (!event.extra.__serialized__) {
              return null;
            }
            let realErrMsg = event.extra.__serialized__.error ? event.extra.__serialized__.error.message : null;
            realErrMsg = realErrMsg || event.extra.__serialized__.message;
            // this is a useless error message that masks the actual error.  Lets try to set it properly
            event.exception.values[0].value = realErrMsg;
            event.message = realErrMsg;
          }
          return event;
        }
      });

@kamilogorek as a vendor you could also open a ticket with the framework. I’m sure it would get some attention.

Thank you for the workaround @gchronos! I hope there will be a potential fix anytime soon.

+1, still getting this error no matter how I put it.

sentry.error-handler.ts

export class SentryErrorHandler extends GeneralErrorHandler {
  ...
  handleError(error) {
    ...
    const exception = error.originalError || error.error || error
    Sentry.captureException(exception)
  }
}

package.json

{
  ...
  "@angular/core": "^8.2.11",
  "@sentry/browser": "^5.7.1",
  ...
}

One thing to note: if you will ignore non exception like errors you may miss something which needs to be fixed just because of the wrong error type.

In my case we are using it with Angular 14 like this

{ provide: ErrorHandler, useValue: Sentry.createErrorHandler({ showDialog: false }) },

and it seem to handle every error from every API we have this error for objects like this

{
  error: {
    code: RequestFieldsTypesMismatched, 
    msg: "Something ....", 
    params: [Object]
  }, 
  headers: {
    lazyInit: [Function: <anonymous>], 
    lazyUpdate: None, 
    normalizedNames: [Object]
  }, 
  message: Http failure response for https://api.iterable.com/api/events/track: 400 OK, 
  name: HttpErrorResponse, 
  ok: False, 
  status: 400, 
  statusText: OK, 
  url: https://api.iterable.com/api/events/track
}

OK, thanks. Too bad it’s missing lots of the helpful details you wrote though.

New docs and 5.16.0 just has been released - https://docs.sentry.io/platforms/javascript/angular/ I tried to make it as explicit and detailed as possible, and that’s why it “may look” like a lot of code.

Hi @kamilogorek , what happend to the detailed documentation? Has it been removed since then? The only thing I could find is this: https://docs.sentry.io/platforms/javascript/guides/angular/troubleshooting/#events-with-non-error-exception


  ignoreErrors: [
    'Non-Error exception captured'
  ]

https://docs.sentry.io/clients/javascript/tips/

… you could also open a ticket with the framework. I’m sure it would get some attention.

I just opened a ticket with sentry support and referenced this issue.

I don’t get it how can Sentry claim out of the box setup, it’s completely false.

@Rush provide a reproducible case, where you explain and show what’s wrong, and then we can verify your claim.