Sentry-javascript: Raven.captureException() not capturing metadata

Created on 8 Mar 2018  路  11Comments  路  Source: getsentry/sentry-javascript

Do you want to request a feature or report a bug?

Bug

What is the current behavior?

With this code:

Raven.config(sentryUrl, {tags: {test0: 'test'}}).install();

  Raven.setUserContext({
           test1: 'test',
        });
        Raven.setTagsContext({ test2:'test' });
        Raven.setExtraContext({  test3:'test' });
        Raven.captureException(err.reason, { logger: 'my.module', extra: 'extra', tags: { test4:'test' } });
 Raven.captureMessage(err.reason, { level: 'warning', extra: 'extra', tags: { test5:'test' } });

A warning and an error are logged. The warning has all the specified meta data, the error only test0.

What is the expected behavior?

That captureException captures the same metadata, the same way as captureMessage.

_Which versions of Raven.js, and which browser and OS are affected by this issue?_
_Are you using the CDN (http://ravenjs.com)?_

I used both raven-js version 3.23.1 with webpack and

Tested on Chrome Version 64.0.3282.186 on Windows 10

_Did this work in previous versions of Raven.js?_
Don't know, first time user.

_Are you using hosted Sentry or on-premises? If on-premises, which version (e.g. 8.7.0)?_
Using https://sentry.io (paid account)

Needs Reproduction

Most helpful comment

@wwwouter two things. Make sure that your actual ErrorBoundry is catching what it should (eg. don't trigger error from the same component that implements it - it won't work).

However, more important is that React does bubble all the errors in development mode and this is what happens in your case.

The first event, that doesn't have tags is triggered using global error handler and only second one is yours. It took me a while to debug as it's not obvious, but this is how React works. It doesn't happen in production.

const BadComponent = () => {
  throw new Error("BadComponent");
};

class ErrorBoundary extends React.Component {
  componentDidCatch(error) {
    Raven.captureException(error, {
      tags: {
        something: "awesome"
      }   
    }); 
    Raven.captureException(new Error("foo"), {
      tags: {
        something: "awesome"
      }   
    }); 
  }

  render() {
    return this.props.children;
  }
}

ReactDOM.render(
  <ErrorBoundary>
    <BadComponent />
  </ErrorBoundary>,
  document.getElementById("main")
);

Here are two screenshots of the output

Development

screen shot 2018-03-12 at 16 07 38

Production

screen shot 2018-03-12 at 16 06 59

Hope it helps.

All 11 comments

Not sure if related but isn't extra suppose to be an object?

I just tested it using your code sample, without any modificaitons, and it's all where it should be :)

captureException

screen shot 2018-03-12 at 11 13 33
screen shot 2018-03-12 at 11 14 06
screen shot 2018-03-12 at 11 14 10

captureMessage

screen shot 2018-03-12 at 11 14 19
screen shot 2018-03-12 at 11 14 22
screen shot 2018-03-12 at 11 14 25

As @SimonSchick mentioned, extra in your captureX calls should be an object, otherwise, it's treated as an array of single character values (see screenshot).

Can you post paste link to the broken events or screenshots of them?

Hi @kamilogorek

There seems to be a problem with the type of error

I'm using react and this is my code

  public render() {
        throw new Error('test8a');
  }

public componentDidCatch(error: any, info: any) {
Raven.captureException(error, { tags: {test4: 'test' } });
Raven.captureException(new Error('test_error'), { tags: {test4: 'test' } });

this.setState({ hasError: true, sentryEventId: Raven.lastEventId() });
}

The first one ignores the tag, while the order does log it:
test_error
test8a

Looking at the POST to sentry, there seems to be a difference:

{
  "project":"xxx",
  "logger":"javascript",
  "platform":"javascript",
  "request":{
    "headers":{
      "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36",
      "Referer":"http://localhost:8080/patients"
    },
    "url":"http://localhost:8080/patients"
  },
  "exception":{
    "values":[
      {
        "type":"Error",
        "value":"test8a",
        "stacktrace":{
          "frames":[
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":44494,
              "colno":37,
              "function":"response.json.then",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":140827,
              "colno":18,
              "function":"dispatch",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":219058,
              "colno":18,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":44471,
              "colno":9,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":140827,
              "colno":18,
              "function":"dispatch",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":219061,
              "colno":16,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":219028,
              "colno":29,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":144360,
              "colno":18,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":81984,
              "colno":7,
              "function":"dispatch",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":81678,
              "colno":16,
              "function":"Connect.onStateChange",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":120259,
              "colno":16,
              "function":"Connect.Component.setState",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":127891,
              "colno":7,
              "function":"Object.enqueueSetState",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132368,
              "colno":12,
              "function":"scheduleWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132411,
              "colno":11,
              "function":"scheduleWorkImpl",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132557,
              "colno":7,
              "function":"requestWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132646,
              "colno":7,
              "function":"performWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132693,
              "colno":24,
              "function":"performWorkOnRoot",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132045,
              "colno":7,
              "function":"renderRoot",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":122117,
              "colno":27,
              "function":"invokeGuardedCallback",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":122260,
              "colno":16,
              "function":"Object.invokeGuardedCallbackDev",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":107334,
              "colno":21,
              "function":"HTMLUnknownElement.wrapped",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":122221,
              "colno":14,
              "function":"HTMLUnknownElement.callCallback",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":131967,
              "colno":26,
              "function":"workLoop",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":131903,
              "colno":16,
              "function":"performUnitOfWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":129904,
              "colno":16,
              "function":"beginWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":129529,
              "colno":12,
              "function":"updateClassComponent",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":129552,
              "colno":31,
              "function":"finishClassComponent",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":208871,
              "colno":15,
              "function":"PatientsList.render",
              "in_app":true
            }
          ]
        }
      }
    ]
  },
  "culprit":"http://localhost:8080/scripts/app.js",
  "trimHeadFrames":0,
  "extra":{
    "session:duration":572
  },
  "breadcrumbs":{
    "values":[
      {
        "timestamp":1520860418.832,
        "type":"http",
        "category":"fetch",
        "data":{
          "method":"GET",
          "url":"/api/session",
          "status_code":200
        }
      }
    ]
  },
  "event_id":"xxx"
}
{
  "project":"xxx",
  "logger":"javascript",
  "platform":"javascript",
  "request":{
    "headers":{
      "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36",
      "Referer":"http://localhost:8080/patients"
    },
    "url":"http://localhost:8080/patients"
  },
  "exception":{
    "values":[
      {
        "type":"Error",
        "value":"test_error",
        "stacktrace":{
          "frames":[
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":44494,
              "colno":37,
              "function":"response.json.then",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":140827,
              "colno":18,
              "function":"dispatch",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":219058,
              "colno":18,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":44471,
              "colno":9,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":140827,
              "colno":18,
              "function":"dispatch",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":219061,
              "colno":16,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":219028,
              "colno":29,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":144360,
              "colno":18,
              "function":"?",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":81984,
              "colno":7,
              "function":"dispatch",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":81678,
              "colno":16,
              "function":"Connect.onStateChange",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":120259,
              "colno":16,
              "function":"Connect.Component.setState",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":127891,
              "colno":7,
              "function":"Object.enqueueSetState",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132368,
              "colno":12,
              "function":"scheduleWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132411,
              "colno":11,
              "function":"scheduleWorkImpl",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132557,
              "colno":7,
              "function":"requestWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132646,
              "colno":7,
              "function":"performWork",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132696,
              "colno":42,
              "function":"performWorkOnRoot",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":131729,
              "colno":9,
              "function":"commitRoot",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":122117,
              "colno":27,
              "function":"invokeGuardedCallback",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":122260,
              "colno":16,
              "function":"Object.invokeGuardedCallbackDev",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":107334,
              "colno":21,
              "function":"HTMLUnknownElement.wrapped",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":122221,
              "colno":14,
              "function":"HTMLUnknownElement.callCallback",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":131635,
              "colno":9,
              "function":"commitAllLifeCycles",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":132289,
              "colno":18,
              "function":"commitErrorHandling",
              "in_app":true
            },
            {
              "filename":"http://localhost:8080/scripts/app.js",
              "lineno":95172,
              "colno":32,
              "function":"UnconnectedCatchingComponent.componentDidCatch",
              "in_app":true
            }
          ]
        }
      }
    ]
  },
  "culprit":"http://localhost:8080/scripts/app.js",
  "trimHeadFrames":0,
  "tags":{
    "test4":"test"
  },
  "extra":{
    "session:duration":645
  },
  "breadcrumbs":{
    "values":[
      {
        "timestamp":1520860418.832,
        "type":"http",
        "category":"fetch",
        "data":{
          "method":"GET",
          "url":"/api/session",
          "status_code":200
        }
      },
      {
        "timestamp":1520860419.011,
        "category":"sentry",
        "message":"Error: test8a",
        "event_id":"",
        "level":"error"
      },
      {
        "timestamp":1520860419.056,
        "message":"The above error occurred in the <PatientsList> component:\n    in PatientsList (created by RouterContext)\n    in UnconnectedCatchingComponent (created by Connect(UnconnectedCatchingComponent))\n    in Connect(UnconnectedCatchingComponent) (created by AppNext)\n    in div\n    in Unknown (created by AppNext)\n    in IntlProvider (created by AppNext)\n    in AppNext (created by Connect(AppNext))\n    in Connect(AppNext) (created by AppSwitcher)\n    in AppSwitcher (created by Connect(AppSwitcher))\n    in Connect(AppSwitcher) (created by RouterContext)\n    in RouterContext (created by Router)\n    in Router\n    in Provider\n\nReact will try to recreate this component tree from scratch using the error boundary you provided, UnconnectedCatchingComponent.",
        "level":"error",
        "category":"console"
      }
    ]
  },
  "event_id":"xxx"
}

@wwwouter two things. Make sure that your actual ErrorBoundry is catching what it should (eg. don't trigger error from the same component that implements it - it won't work).

However, more important is that React does bubble all the errors in development mode and this is what happens in your case.

The first event, that doesn't have tags is triggered using global error handler and only second one is yours. It took me a while to debug as it's not obvious, but this is how React works. It doesn't happen in production.

const BadComponent = () => {
  throw new Error("BadComponent");
};

class ErrorBoundary extends React.Component {
  componentDidCatch(error) {
    Raven.captureException(error, {
      tags: {
        something: "awesome"
      }   
    }); 
    Raven.captureException(new Error("foo"), {
      tags: {
        something: "awesome"
      }   
    }); 
  }

  render() {
    return this.props.children;
  }
}

ReactDOM.render(
  <ErrorBoundary>
    <BadComponent />
  </ErrorBoundary>,
  document.getElementById("main")
);

Here are two screenshots of the output

Development

screen shot 2018-03-12 at 16 07 38

Production

screen shot 2018-03-12 at 16 06 59

Hope it helps.

So if I understand it correctly, in development mode the first captureException is ignored?

Well, not really ignored. It's correctly caught by Raven, as it's a proper error. It's React that bubbles it up to the global error handler in development, where, in production, it doesn't.

It is also caught in componentDidCatch, so if it's bubbled, shouldn't that result in the logging of 3 exceptions, with two that have the something:awesome tag?

That's exactly what happens. See my first screenshot :)

Sorry if this is becoming more of on-boarding than an actual issue, but if I look at my dashboard I see only one event. Shouldn't there be two for test8a?

So if one has a tag and the other hasn't, does this result in 1 issue with 2 events? If so, should't the tag be visible? Or should there be 2 issues, with both 1 event?

No worries :) Ok, so there are 2 things going on.

Shouldn't there be two for test8a?

Not in this scenario:

  componentDidCatch(error) {
    Raven.captureException(error, {
      tags: {
        something: "awesome"
      }   
    }); 
    Raven.captureException(new Error("foo"), {
      tags: {
        something: "awesome"
      }   
    }); 
  }

When configured like this, notice that first captureException is exactly the same error as the one caught by the global handler. This means that they are duplicates. If you set Raven.debug = true, then you can see that it's being dropped, as we calculate duplicates based on the exception itself and a stacktrace, which in this case are the same.

screen shot 2018-03-13 at 16 10 11

If you change the order, so it's:

  • global hander for thrown error
  • your custom error, eg. new Error('foo')
  • captureException for didCatchException

Then it's not treated as a duplicate, as 2 consecutive exceptions are never the same. In this case, we send all 3 of them.

screen shot 2018-03-13 at 16 11 17

So if one has a tag and the other hasn't, does this result in 1 issue with 2 events?

That's correct. As mentioned above, events are calculated based on exception and stacktrace value, and tags are associated to the specific event.

If so, should't the tag be visible? Or should there be 2 issues, with both 1 event?

If we'd do that, it'd be very noisy. We try to group them as much as possible and assume that the same exception with the same stacktrace will always have the same tags, as it's basically thrown in the same place.

馃 Thanks for the detailed explanation!

Was this page helpful?
0 / 5 - 0 ratings