raven-python
raven-python copied to clipboard
'NoneType' object has no attribute '__module__'
We are getting a Sentry issue reported by Sentry. The issue happens in Celery executed code.
MESSAGE
Signal handler <bound method SentryCeleryHandler.process_failure_signal of <raven.contrib.celery.SentryCeleryHandler object at 0x7f7ba702e450>> raised: AttributeError("'NoneType' object has no attribute '__module__'",)
Exception:
AttributeError 'NoneType' object has no attribute '__module__'
The offending code looks to be this:
def should_capture(self, exc_info): exc_type = exc_info[0] exc_name = '%s.%s' % (exc_type.__module__, exc_type.__name__) exclusions = self.ignore_exceptions
Python: 2.7.11 raven-python: 5.32.0 celery: 4.0.2
Same issue.
We are experiencing this issue. The bug appears to be within the Celery contrib file and/or in code that patches captureException()
.
Looking at our Sentry traceback, it is curious that process_failure_signal()
does not pass an exc_info
kwarg to captureException()
, but that kwarg indeed shows up in captureException()
as [None, None, None]
. I imagine this method is being modified to inject exc_info
in some way, but it's hard to debug further without knowing more about how Sentry patches these various handlers.
P.S. Looks similar to https://github.com/getsentry/raven-python/issues/936.
A possible reason for this is that you might have multiple (custom) celery applications instantiated. This installs multiple SentryCeleryHandler
's and therefore multiple receivers are connected to the task_failure
signal.
The first time the receiver is called everything worked fine, but in the second call, it failed. captureException()
doesn't pass the exc_info and rather calls sys.exc_info() which returns None after the first call. Most probably because the exception happened in a different thread related to different celery application.
My solution was to make sure I only have a single Celery instance that configures Sentry i.e. this is instantiated only once.
class SentryCelery(celery.Celery):
"""Celery subclass that logs exceptions to Sentry"""
def on_configure(self):
""" Configure sentry client. """
client = raven.Client(tags={'worker': self.main}, **settings.SENTRY_CONFIG)
# register a custom filter to filter out duplicate logs
register_logger_signal(client)
# hook into the Celery error handler
register_signal(client)
You could place a breakpoint and see how many times process_failure_signal
is called for a single exception to falsify this reason. An easier approach would be placing the breakpoint on init method of your custom celery class.
We run into this as well.
Does anyone mind writing a couple of lines to explain what the workaround could be in Django? I am not completely sure on how to get around this, really.
This seems to be an old issue but i am running into the same issue.
File "/usr/local/lib/python2.7/dist-packages/raven/base.py", line 814, in captureException
'raven.events.Exception', exc_info=exc_info, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/raven/base.py", line 625, in capture
elif not self.should_capture(exc_info):
File "/usr/local/lib/python2.7/dist-packages/raven/base.py", line 818, in should_capture
exc_name = '%s.%s' % (exc_type.__module__, exc_type.__name__)
AttributeError: 'NoneType' object has no attribute '__module__'
This seems to happen when you try to capture an exception but there has not been an exception. e.g.
sys.exc_info() == (None, None, None)
And since the tuple (None, None, None) != None
the code continues i think the rule 622 should be:
if exc_info is not None and exc_info is not (None, None, None):
I will make a PR for this when i have the time
I had the same issue and solved it by replacing
exc_info is not None
with
exc_info is not None and sorted(exc_info) != sorted((None, None, None))
I only got this problem when I tried to use client.captureException outside of a try/except block.
Sort of workaround for using captureException
outside try/except block:
import sys
import raven
def get_exc_info():
exc_info = sys.exc_info()
if exc_info[0] is None:
return None
return exc_info
def capture_exception(error)
sentry = raven.Client(...)
exc_info = get_exc_info()
if exc_info:
sentry.captureException(exc_info)
else:
sentry.captureMessage(error)