Skip to main content

flask-error-handling

#post

flask-error-handling

  • keep request-specific error handling behavior (e.g. flask.abort or otherwise responding to a request) as close the request handler as possible and decoupled from any modules that may be called outside of a request contexty
  • e.g. I put some flask.abort(404) calls in a data_manager file called both during request + during admin tasks like rebuilding the app’s cache storage bucket (where flask is not relevant and a request is not in progress)

Create a custom error class:

# all we care about is the name
class UserNotFoundError(ValueError):
    pass
 
# we care about some metadata too
class GroupNotFoundError(ValueError):
    """
    Custom exception to be raised when a group label cannot be found in memory or the Google Cloud Storage bucket.
    """
 
    status_code_default = 404
 
    def __init__(self, message, group_label=None, status_code=None) -> None:
        super().__init__()
        self.group_label = group_label
        self.message = message
        self.status_code = (
            status_code if status_code is not None else self.status_code_default
        )
 
    def to_dict(self) -> GroupNotFoundErrorDict:
        return {
            "group_label": self.group_label,
            "message": self.message,
            "status_code": self.status_code,
        }

Register an error handler:

How do I get this to actually catch the exceptions and call the handler before they become 500s?

  • Don’t wrap handler code with try/except
  • If you do, the error won’t bubble up to the handler
  • There’s no need for a blanket try/except Exception as flask will already catch those for you as 500 responses
  • So, if your error handler isn’t being called and you’re still getting 500, remove any try/except wrapping your handler body
@app.errorhandler(GroupNotFoundError)
def handle_group_not_found_error(
    error: GroupNotFoundError,
) -> tuple[PercentilesResponse, int]:
    e = error.to_dict()
    group_label, status_code = e["group_label"], e["status_code"]
    message = "Percentiles: group not found in any cache"
 
    slogger.error(message, group_label=group_label)
 
    return create_error_response(
        error=EndpointError(
            message=message, exception=None, requestId=flask.g.request_id
        ),
        status_code=status_code,
    )

Or catch the custom exception and call the error handler explicitly?

Which is better? Is one better in all cases? Catching seems to be working better…

  • Ask Denton!
except GroupNotFoundError as e:
    return handle_group_not_found_error(e)

Handling Application Errors — Flask Documentation (3.0.x)