Search code examples
pythonerror-handlingflaskhttp-error

Global error handler for any exception


Is there a way to add a global catch-all error handler in which I can change the response to a generic JSON response?

I can't use the got_request_exception signal, as it is not allowed to modify the response (http://flask.pocoo.org/docs/0.10/signals/).

In contrast all signal handlers are executed in undefined order and do not modify any data.

I would prefer to not wrap the app.handle_exception function as that feels like internal API. I guess I'm after something like:

 @app.errorhandler()
 def handle_global_error(e):
     return "Global error"

Note the errorhandler does not take any parameters, meaning it would catch all exceptions/status codes which does not have a specific error handler attached to them. I know I can use errorhandler(500) or errorhandler(Exception) to catch exceptions, but if I do abort(409) for example, it will still return a HTML response.


Solution

  • You can use @app.errorhandler(Exception):

    Demo (the HTTPException check ensures that the status code is preserved):

    from flask import Flask, abort, jsonify
    from werkzeug.exceptions import HTTPException
    
    app = Flask('test')
    
    @app.errorhandler(Exception)
    def handle_error(e):
        code = 500
        if isinstance(e, HTTPException):
            code = e.code
        return jsonify(error=str(e)), code
    
    @app.route('/')
    def index():
        abort(409)
    
    app.run(port=1234)
    

    Output:

    $ http get http://127.0.0.1:1234/
    HTTP/1.0 409 CONFLICT
    Content-Length: 31
    Content-Type: application/json
    Date: Sun, 29 Mar 2015 17:06:54 GMT
    Server: Werkzeug/0.10.1 Python/3.4.3
    
    {
        "error": "409: Conflict"
    }
    
    $ http get http://127.0.0.1:1234/notfound
    HTTP/1.0 404 NOT FOUND
    Content-Length: 32
    Content-Type: application/json
    Date: Sun, 29 Mar 2015 17:06:58 GMT
    Server: Werkzeug/0.10.1 Python/3.4.3
    
    {
        "error": "404: Not Found"
    }
    

    If you also want to override the default HTML exceptions from Flask (so that they also return JSON), add the following before app.run:

    from werkzeug.exceptions import default_exceptions
    for ex in default_exceptions:
        app.register_error_handler(ex, handle_error)
    

    For older Flask versions (<=0.10.1, i.e. any non-git/master version at the moment), add the following code to your application to register the HTTP errors explicitly:

    from werkzeug import HTTP_STATUS_CODES
    for code in HTTP_STATUS_CODES:
        app.register_error_handler(code, handle_error)