Flask-restful: Different error responses based on DEBUG flag

Created on 29 Mar 2016  路  8Comments  路  Source: flask-restful/flask-restful

Not sure if this is a bug or a gap in my understanding (I am very new to Flask, and Python in general).

Since I felt constrained by the dict-based error handling in Flask-Restful, I used the 'errorhandler' decorator provided by Flask. The issue is, the errorhandlers work fine when DEBUG=True (and show custom error responses that I have set up), but show a cryptic {'message': 'Internal Server Error'} when DEBUG=False.

After a lot of struggle, I figured out that it was due to 2 reasons:

  1. The PROPAGATE_ERRORS flag being set and unset on DEBUG=True/False.
  2. This snippet of code in the flask_restful/__init__.py file:
        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),
            }

which raises the exception and lets the flask errorhandler deal with it if propagate_exceptions is True, but handles the exception by itself if otherwise.

I have 2 suggestions:

  1. You should mention in the documentation that Flask-Restful overrides the default Flask error handlers.
  2. Since you _are_ overriding the error handlers, should you even care whether propagate_exceptions is True or False?

It looks weird to me that flask_restful handles error responses differently based on the DEBUG flag. Is there a way I can disable FR error handling? Is there a flexible error handing option in FR so that I can avoid the Flask errorhandler ?

Most helpful comment

If debug mode is disabled, the PROPAGATE_EXCEPTIONS setting can still be set to True explicitly:

app.config['PROPAGATE_EXCEPTIONS'] = True

All 8 comments

I have this question too.
And there is a same question in stackoverflow, but nobody answer.
http://stackoverflow.com/questions/36076650/flask-restful-taking-over-exception-handling-from-flask-during-non-debug-mode

I have a similar problem.

My code look like this:

apiv1 = Blueprint('apiv1', __name__)
api = Api(apiv1)

@apiv1.errorhandler(CustomException)
def hander_(error):
    return jsonify({}), 400

In debug mode, the flask errorhandler works fine.

But in none-debug mode, the errorhandler will not work. It never catch the CustomException. Server cause return 500 instead.

Yes, this is an issue with flask-restful:

As I've understood flask-restful tries to unify the output format of all errors returned by the app. So far that's reasonable. It does this however by completely overriding the usual flask error handling code (for all routes under its control). This is the problem.

There was an attempt to rewrite the error-handling code at some point, but the pull-request was given up. -> #544

Has this been resolved? Or has anyone found a safe workaround?

@harrylewis The workaround is mentioned in #280 comments.

If debug mode is disabled, the PROPAGATE_EXCEPTIONS setting can still be set to True explicitly:

app.config['PROPAGATE_EXCEPTIONS'] = True

The workaround in #280 also works, but does so by completely bypassing flask_restful error handling which I think is a bit of a blunt solution.

Setting PROPAGATE_EXCEPTIONS = True also works, but is a bad solution. When flask_restful is initialised with a flask app, it hijacks Flask's native error handler functions - app.handle_user_exception and app.handle_exception.

When PROPAGATE_EXCEPTIONS = True, flask_restful will forego it's own error handler, and fall back to these original flask app.handle_user_exception and app.handle_exception implementations. This means you can _either_ use flask errorhandlers OR flask_restful's error handler (you might want both).

What these original Flask error handler functions do is check to see if there is a defined custom handler for that given error (a function decorated by @app.errorhandler) and let that function handle the error - which is what we want. Hence why setting PROPAGATE_EXCEPTIONS = True makes @app.errorhandler functions work.

The problem with this is that Flask also does something with PROPAGATE_EXCEPTIONS. In Flask when this is True and there is no defined handler for the error, it will reraise the exception instead of returning a stock werkzeug.exceptions.InternalServerError when the flag is False. This is bad because this single flag _does 2 distinct but deceptively similar things_, and there is no way to do one, and not the other.

I propose:

  • The flask_restful error handler should check if there is a flask error handler for the given error and use that.
  • Additionally if we actually want to forego the flask_restful error handler, flask_restful should do so using a _different_ config flag value. Something like USE_FLASK_ERROR_HANDLER perhaps.

Thoughts? Happy to open a PR with these changes.

@ramshaw888 I think you should open a PR implementing the solution using a config flag value

Was this page helpful?
0 / 5 - 0 ratings

Related issues

BenjaVR picture BenjaVR  路  4Comments

f9n picture f9n  路  4Comments

svvitale picture svvitale  路  8Comments

n0trace picture n0trace  路  3Comments

benghaziboy picture benghaziboy  路  3Comments