Falcon: Error using Raven WSGI Middleware

Created on 8 May 2014  路  5Comments  路  Source: falconry/falcon

I am attempting to use the Raven WSGI Middleware in order to log errors to Sentry, as per the docs.

However after doing this and introducing an artificial error into a Resource, I see the error logged as expected in Sentry but the following is thrown by the wsgiref server. This then results in the client receiving no content, rather than the usual 500 response.

12:11:17 web.1     | Traceback (most recent call last):
12:11:17 web.1     |   File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/wsgiref/handlers.py", line 86, in run
12:11:17 web.1     |     self.finish_response()
12:11:17 web.1     |   File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/wsgiref/handlers.py", line 131, in finish_response
12:11:17 web.1     |     self.close()
12:11:17 web.1     |   File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/wsgiref/simple_server.py", line 33, in close
12:11:17 web.1     |     self.status.split(' ',1)[0], self.bytes_sent
12:11:17 web.1     | AttributeError: 'NoneType' object has no attribute 'split'
12:11:17 web.1     | 127.0.0.1 - - [08/May/2014 12:11:17] "GET /v1/nodes/2258311 HTTP/1.1" 500 59
12:11:17 web.1     | ----------------------------------------
12:11:17 web.1     | Exception happened during processing of request from ('127.0.0.1', 51394)
12:11:17 web.1     | Traceback (most recent call last):
12:11:17 web.1     |   File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 295, in _handle_request_noblock
12:11:17 web.1     |     self.process_request(request, client_address)
12:11:17 web.1     |   File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 321, in process_request
12:11:17 web.1     |     self.finish_request(request, client_address)
12:11:17 web.1     |   File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 334, in finish_request
12:11:17 web.1     |     self.RequestHandlerClass(request, client_address, self)
12:11:17 web.1     |   File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 649, in __init__
12:11:17 web.1     |     self.handle()
12:11:17 web.1     |   File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/wsgiref/simple_server.py", line 124, in handle
12:11:17 web.1     |     handler.run(self.server.get_app())
12:11:17 web.1     |   File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/wsgiref/handlers.py", line 92, in run
12:11:17 web.1     |     self.close()
12:11:17 web.1     |   File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/wsgiref/simple_server.py", line 33, in close
12:11:17 web.1     |     self.status.split(' ',1)[0], self.bytes_sent
12:11:17 web.1     | AttributeError: 'NoneType' object has no attribute 'split'
12:11:17 web.1     | ----------------------------------------

Not really sure where I've gone wrong, or if this is a bug with Falcon itself. Any help would be much appreciated.

Most helpful comment

@muodov I'm a bit late probably
here is a code snippet I'm using to send errors to self-hosted sentry
have no idea if it's the right way of handling unknown errors, but it works :)
and I'm still experimenting - falcon noob here

import falcon
from raven import Client
from svc import conf

app = falcon.API()

if conf.sentry_dsn:
    client = Client(conf.sentry_dsn)

    def internal_error_handler(ex, req, resp, params):
        data = {
            'request': {
                'url': req.url,
                'method': req.method,
                'query_string': req.query_string,
                'env': req.env,
                'data': req.params,
                'headers': req.headers,
            }
        }
        message = isinstance(ex, falcon.HTTPError) and ex.title or str(ex)
        ident = client.captureException(message=message, data=data)

        if not isinstance(ex, falcon.HTTPError):
            resp.status = falcon.HTTP_500
            resp.body = ('A server error occurred (reference code: "%s"). '
                         'Please contact the administrator.' % ident)
        else:
            raise ex

    app.add_error_handler(Exception, internal_error_handler)

hope it will be useful for someone searching for sentry integration

All 5 comments

I noticed this from your log:

    self.status.split(' ',1)[0], self.bytes_sent
AttributeError: 'NoneType' object has no attribute 'split'

According to https://github.com/python/cpython/blob/master/Lib/wsgiref/handlers.py#L225 theself.status variable is set directly from the WSGI start_response callback. So, the HTTP status line set by the middleware or the app is missing a space.

My first guess is that something is setting the response status to a string that only includes the status code. For example, in the app if you did this, it would cause the error:

resp.status = '204'

Thanks for taking the time to reply Kurt, much appreciated. You've given me enough to go away and investigate further. I'll let you know if I find a solution.

As suggested, this issue is resolved by ensuring that the status is set correctly. Tested again with the current version of Raven (5.1.1) and it's working fine.

@neilalbrock how exactly did you ensure that status is correct? I am trying to get raven report unhandled exceptions in the app, but I get the same error.

@muodov I'm a bit late probably
here is a code snippet I'm using to send errors to self-hosted sentry
have no idea if it's the right way of handling unknown errors, but it works :)
and I'm still experimenting - falcon noob here

import falcon
from raven import Client
from svc import conf

app = falcon.API()

if conf.sentry_dsn:
    client = Client(conf.sentry_dsn)

    def internal_error_handler(ex, req, resp, params):
        data = {
            'request': {
                'url': req.url,
                'method': req.method,
                'query_string': req.query_string,
                'env': req.env,
                'data': req.params,
                'headers': req.headers,
            }
        }
        message = isinstance(ex, falcon.HTTPError) and ex.title or str(ex)
        ident = client.captureException(message=message, data=data)

        if not isinstance(ex, falcon.HTTPError):
            resp.status = falcon.HTTP_500
            resp.body = ('A server error occurred (reference code: "%s"). '
                         'Please contact the administrator.' % ident)
        else:
            raise ex

    app.add_error_handler(Exception, internal_error_handler)

hope it will be useful for someone searching for sentry integration

Was this page helpful?
0 / 5 - 0 ratings