0

I've built a flask application and I try to catch unhandled application errors from my routes using the errorhandler decorator.

I've a main.py which looks like this,

app = Flask(__name__)
api = Api(app)

api.add_resource(Ping, '/ping')

@app.errorhandler(500)
def internal_server_error(error):
    print "caught internal server error"
    return "This page does not exist", 500

The route Ping is in another file, here is a sample version of the file

class Ping(Resource):
    def get(self):

        raise
        return {}, 200

I've placed a raise to try and reproduce a 500 Internal server error. Here is a sample error raised by my application

[2019-01-26 10:37:36,449] ERROR in app: Exception on /events/v1/monitoring/ping [GET]
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python2.7/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/usr/local/lib64/python2.7/site-packages/flask_restful/__init__.py", line 480, in wrapper
    resp = resource(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/flask/views.py", line 88, in view
    return self.dispatch_request(*args, **kwargs)
  File "/usr/local/lib64/python2.7/site-packages/flask_restful/__init__.py", line 595, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/myapi/ping.py", line 17, in get
    raise
TypeError: exceptions must be old-style classes or derived from BaseException, not NoneType
127.0.0.1 - - [26/Jan/2019 10:37:36] "GET /ping HTTP/1.0" 500 -

For reasons I haven't been able to figure, the @app.errorhandler decorator doesn't catch any 500 error that come are raised by the application.

user6434902
  • 49
  • 3
  • 11

2 Answers2

6

I think you are using flask-restful. In order to your error handler be catched you should set the config param PROPAGATE_EXCEPTIONS to True in your config file.

Flask restful has its own error handler which differs from that of Flask. This is an extract:

[...]

if not isinstance(e, HTTPException) and current_app.propagate_exceptions:
    exc_type, exc_value, tb = sys.exc_info()
    if exc_value is e:
        raise
    else:
        raise e

headers = Headers()
if isinstance(e, HTTPException):
    code = e.code
    default_data = {
        'message': getattr(e, 'description', http_status_message(code))
    }
    headers = e.get_response().headers
else:
    code = 500
    default_data = {
        'message': http_status_message(code),
    }
[...]

After setting PROPAGATE_EXCEPTIONS to True you should add at least these two error handlers:

@app.errorhandler(Exception)
def internal_server_error(e):
    return jsonify({'msg': 'Internal server error'}), 500

@app.errorhandler(500)
def internal_server_error_500(e):
    return jsonify({'msg': 'Internal server error'}), 500

So, the first one will catch any exception raised at application level, even your own custom exceptions and the second one will catch any 500 error, for example raised on abort(500).

j2logo
  • 649
  • 4
  • 9
  • Yes, I'm using flask-restful Once I set the config, do you know how to catch all 500 Internal server errors and gracefully deal with them? – user6434902 Jan 30 '19 at 05:12
1

Try this one instead:

@app.errorhandler(Exception)
  • In my application I have multiple errorhandlers. One for the general exception case, just as Александр has done here. Then a few additional handlers for 500, 403, 404, etc.. Maybe you will have better luck using both? – John McCabe Jan 26 '19 at 15:36