How do you handle errors that occur in middleware? #10404
-
First Check
Commit to Help
Example Codeclass OAuth2Middleware:
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
try:
await self.auth_middleware(scope, receive, send)
except Exception as e:
raise OAuth2Error(403, str(e)) # OAuth2Error inherits HTTPExceptionDescriptionWell, I have a custom middleware where at the @app.exception_handler(OAuth2Error)
async def error_handler(request: Request, exc: OAuth2Error):
return RedirectResponse(url="/", status_code=303) # ignore the error and go to homepageWhen the exception is raised from a router, this way of error handling works perfectly, but it does not work in my case when it is raised from a middleware. Should I do some hacks, such as changing the request context or the Operating SystemLinux Operating System DetailsNo response FastAPI Version0.103.2 Pydantic Version2.4.2 Python Version3.10.7 Additional ContextNo response |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 7 replies
-
|
The processing of middleware in fastapi belongs to an onion model, so if you want to handle this error, you need to register a middleware in the outer layer to capture the error. class ExceptionMiddleware(BaseHTTPMiddleware):
"""Exception middleware"""
async def dispatch(
self,
request: Request,
call_next: RequestResponseEndpoint,
) -> Response:
try:
response: Response = await call_next(request)
except (ValidationError, CancelledError, Exception,
OAuth2Middleware) as exc:
if isinstance(exc, (SHTTP, FastapiHTTPException, OAuth2Middleware)):
err_msg: dict = exc.detail
content = {
"code": err_msg.get('code'),
"msg": err_msg.get('msg'),
"detail": {}
}
return JSONResponse(
status_code=exc.status_code, content=content
)
else:
log.error(traceback.format_exc())
return JSONResponse(
content={
"code": 500,
"msg": "The programmer brother didn't get enough sleep and the system crashed!",
"detail": {
# "msg": "The server is abnormal, please contact the backend development!",
}
},
return response |
Beta Was this translation helpful? Give feedback.
-
|
I have the same issue. Couldn't find the answer yet. Have you found the answer @ArtyomVancyan? Thanks! |
Beta Was this translation helpful? Give feedback.
-
|
FastAPI is implemented based on starlette. The processing of middleware belongs to an onion model.
Moreover, in starlette, exceptions are divided into two types: Exception and Error.
In the processing of starlette, Error has only one Handler (with an HTTP status code of 500 or when the handled error is an Exception), which is wrapped by ServerErrorMiddleware. While Exception has multiple Handlers and is wrapped by ExceptionMiddleware. My approach is to define a global Exception, have subclasses inherit from it, register a global ErrorHandler, throw an exception in the user middleware, and then handle the exception in the ErrorHandler and return it to the front end. # define base exception
class BaseException(Exception):
def __init__(self, message: str, status_code: int):
self.message = message
self.status_code = status_code
super().__init__(message)
def content(self):
return {"error_msg": self.message}
# define custom exception
class QuotaNotEnoughException(BaseException):
def __init__(self):
super().__init__("quota not enough", 403)
# register error handler
@fast_app.exception_handler(Exception)
async def unicorn_exception_handler(request: Request, exc: Exception):
if isinstance(exc, BaseException):
return JSONResponse(
status_code=exc.status_code,
content=exc.content(),
)
return JSONResponse(
status_code=500,
content={"error_msg": "Internal Server Error"},
)
# user middleware
@fast_app.middleware("http")
async def auth_middleware(request: Request, call_next):
if xxx:
raise QuotaNotEnoughException()
return await call_next(request) |
Beta Was this translation helpful? Give feedback.
-
|
I'm also struggling on the error handling raised from the middleware. Normal using Raising above from the middleware Example of not working. Add the RBACMiddleware to fastapi app: In the above example it always raises the 500 internal server error: I have also tried to add a custom exception_handler: This still crashes the code but does not send the 500 response to the client, only there are no details/body set. Therefore it is hard to know what is going wrong on the client site. The response is not the same like using |
Beta Was this translation helpful? Give feedback.
-
|
From Starlette's docs: https://www.starlette.io/exceptions/#httpexception
Also: https://www.starlette.io/exceptions/#errors-and-handled-exceptions
So, exception handlers will not work for As a solutions, you can:
|
Beta Was this translation helpful? Give feedback.
From Starlette's docs: https://www.starlette.io/exceptions/#httpexception
Also: https://www.starlette.io/exceptions/#errors-and-handled-exceptions
So, exception handlers will not work for
HTTPExceptionsraised by middlewares, because they are raised outside of theExceptionMiddleware…