fastapi: cors and error status 500 and handle it in frontend
First check
- I used the GitHub search to find a similar issue and didn’t find it.
- I searched the FastAPI documentation, with the integrated search.
- I already searched in Google “How to X in FastAPI” and didn’t find any information.
Description
When there is 500 error happens, the response header contains no information about cors. The browser console says: ‘Reason: CORS header ‘Access-Control-Allow-Origin’ missing’
I want to check the status code in in frontend(vue) with axios and alert a error message, but there is no error.response.status in axios catch. I guess it is related to the cors bedore the browser complains it in console.
Code to generate error 500
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware
import pandas as pd
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=['*'],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/error")
async def five_hundrend_error():
df = pd.read_csv("not_exists.csv")
return df.to_dict('records')
Below is the response header of 500. There is no cors info.
HTTP/1.1 500 Internal Server Error
date: Sat, 07 Dec 2019 10:01:24 GMT
server: uvicorn
content-length: 21
content-type: text/plain; charset=utf-8
Is it intended to behave like this? Or it may be a bug?
EDIT: I finally get the 500 error handled in frontend after read the axios doc. I keep it open because I’m still curious about it.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 10
- Comments: 16 (3 by maintainers)
@statueofmike I had the same issue recently, you don’t need to wrap each endpoint with try/catch manually, you can do that once in the custom exception-catching middleware.
Assuming that browser sends request from localhost:3000 to api on port 8080, here is an example that returns 500 status code together with CORS headers even though exception is thrown in the endpoint. catch_exceptions_middleware does the trick, the important thing is to use it before CORS middleware is used.
If you receive a 500 response that means you have an error in your backend app code (Python using FastAPI).
It doesn’t have anything to do with CORS. If you have an error, your app won’t be able to send any headers used for CORS. But the problem is not at CORS, is before that.
Check your error logs, from your Python code, where you run Uvicorn.
Thanks for the discussion and ideas here!
On the other side, let me suggest you all to try sentry.io
It has a free tier, and it might change your life 😉
In some cases, it can detect and show errors even better than what you could while debugging locally. And for 500 errors that you want to be sure you know what’s having errors, even during production, that could be a vital tool.
For anyone who comes across this in the future in search of a solution, below is how we’ve decided to handle this using a custom 500 exception handler.
@tiangolo sentry is a good suggestions and should be implemented by the masses, but the problem i think comes with how this error is reported to the user.
What’s happening is the route faults and the caller is receiving a browser message saying ‘CORS header ‘Access-Control-Allow-Origin’ missing’ obscuring the actual error. This causes a wild goose chase in CORS settings on servers and client for some amount of time before someone realizes they should check the server logs for the actual error, even if they’re using sentry. After the realization is CORS headers aren’t sent during default exception handling we Google and stumble on this thread followed by a copy/paste of someone’s work around.
I think this issue is one of friction/confusion which isn’t solved by improving log ingestion. If CORS is misconfigured then a CORS error should be displayed, but if CORS is configured correctly then the CORS error should not appear, and the 500 error would now suggest to the user “check the server logs”. This is, in my experience, how other frameworks function.
I also have this question. I have confusion with a developer who thinks there is a CORS issue when receiving any 500 error response, though the
access-control-allow-originheaders are present for all other responses.As a workaround, I noticed that if I manually do:
Then the CORS headers are included in the 500 response.
I apologize if this is just my ignorance of best practices. I expected default 500 responses returned from uncaught Python exceptions to include the CORS headers given in
app.add_middleware. It seems to only include them when I build and return a 500 response.Not providing CORS-related headers in the case of an error is a real antipattern to modern web communication, where CORS is treated as essential and non-negotiable by all common browsers. I don’t think this should be delegated to framework users. Please reopen.
I solved it like this, however it works only if specific exception is given to
exception_handler(didn’t work for me with genericException)more info: https://fastapi.tiangolo.com/tutorial/handling-errors/#install-custom-exception-handlers (also check https://www.starlette.io/exceptions/)
what @rigward proposed in https://github.com/tiangolo/fastapi/issues/775#issuecomment-592946834 works BUT is not an optimal solution IMO
@statueofmike @rigward Thanks for your reply. The idea is to handle the unforeseen error to avoid missing cors header.
@tiangolo Thanks for your suggestion.
Thank you, @tiangolo. I’ve found those app code errors. Right now I keep all my endpoints wrapped in a general try/except and manually return 500 responses to preserve the CORS headers for such cases. Is there a better way to have the CORS headers included for future app errors I haven’t identified?