Raising Exception from ApiRouter does not run the exception handler, returns 500 internal server error instead. FAST API

Viewed 1377

I am raising a custom exception in a Fast API using an API Router added to a Fast API. I am defining the exception class and handler and adding them both using the following code. It was working before and now I am not quite sure what is the issue. The middleware got added so maybe that is the issue?

app = FastAPI()

origins = [
    "*",    # Restrict these in the future?
]

app.include_router(memblock_router.router)
app.include_router(event_router.router)

app.add_exception_handler(UnauthorizedException, unauthorized_exception_handler)
app.add_exception_handler(InvalidParameterException, invalid_parameter_exception_handler)
app.add_exception_handler(DatabaseException, database_exception_handler)
app.add_exception_handler(ElasticsearchException, elasticsearch_exception_handler)
app.add_exception_handler(ParsingException, parsing_exception_handler)
app.add_exception_handler(ForbiddenErrorMessage, forbidden_error_message_exception)
app.add_exception_handler(UnsupportedErrorMessage, unsupported_message)
app.add_exception_handler(RequestValidationError, validation_exception_handler)

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

I am defining the exceptions and handlers like so

class UnauthorizedException(Exception):
    pass

def unauthorized_exception_handler(request: Request, exc: UnauthorizedException):
    print(str(traceback.format_exc()))
    return JSONResponse(status_code=status.HTTP_401_UNAUTHORIZED,
                        content={"error": "unauthorized"},
                        headers=get_response_headers())
1 Answers

I had the same issue and in my case the problem was related with imports. I had a project structure like this:

.
├── Dockerfile
├── app
│   ...
│   ├── main.py
│   ├── repositories
│   │   ├── __init__.py
│   │   └── repository.py
└── requirements.txt

repository.py contained a class of an error I'd like to handle:

# app/repositories/repository.py

class RepositoryError(Exception):
    pass

In main.py I registered a handler for this error:

# app/main.py

...

from repositories.repository import RepositoryError


def get_application() -> FastAPI:
    application = FastAPI(title=PROJECT_NAME, debug=DEBUG, version=VERSION)

    ...

    application.add_exception_handler(RepositoryError, http500_error_handler)

    application.include_router(api_router)

    return application


app = get_application()

if __name__ == '__main__':
    uvicorn.run('app.main:app', host='127.0.0.1', port=8000, reload=True)

As you can see, I used a relative import repositories.repository instead of app.repositories.repository. When I dig deeper into the code where the appropriate error handler is being chosen I saw the following at starlette/exceptions.py:

Imports in debugger

An exception handler registered on the app was bound to the repositories.repository.RepositoryError class, but the caught exception was of the app.repositories.repository.RepositoryError class and these two classes didn't match. When I changed the import to app.repositories.repository.RepositoryError in my main.py everything worked ok.

Related