Here's a self-contained minimal, reproducible, example with my use case:
from fastapi import FastAPI, Form
app = FastAPI()
@app.post("/login/")
async def login(username: str = Form(...), password: str = Form(...)):
return {"username": username}
{
"detail": "There was an error parsing the body"
}
The problem is that it's trying to read form data (multipart), and for that it requires the package python-multipart installed.
It is documented in the docs in FastAPI and Starlette, but forgetting to install it and running the app ends up in that behavior that is not explicit nor obvious. Everything works normally, except that specific path operation, that only breaks after a receiving a request (which is worse).
To make things more complex, the package required is python-multipart. But there's another Python package called just multipart.
And both packages are imported as:
import multipart
This can lead to a problem that is really difficult to debug: an environment with both packages installed, in some runs could import the correct package and everything would work, but in other runs, it could import the other package, which would cause problems. That would make it one of those scary ghost bugs that disappear and appear. :bug: :ghost:
And even worse, the problems will only show up after receiving a request in a path operation that requires reading form data, not at start up.
In FastAPI, the main ways to get form data are quite explicit, using Form, UploadFile, bytes.
That means that it's possible to detect that a path operation will try to read form data on initialization.
I would like FastAPI to raise an error and crash fast when there's a path operation that uses something that requires to read form data, right on initialization (while creating the instances).
In Starlette (or in FastAPI when using the request directly), there's no way to know if the code will try to access form data from the request.
But in FastAPI, as it is declared in function parameters that are read during initialization, it would be possible to error out early.
It should log an error saying that form data requires python-multipart and then raise the exception. This would be triggered right while starting an application.
But it would only raise an exception if there's a path operation that actually requires form data, otherwise, everything would work as normal.
It should ideally also detect if the imported multipart is the correct one or not. If the incorrect one is installed/imported, it should log an error informing that clearly, explaining that multipart is not compatible with python-multipart, that the user has to uninstall multipart and then install python-multipart.
There's a point in code that decides if a path operation should read from JSON or from Form data while creating the request body field for a path operation. Whatever does the check about python-multipart, would ideally run from that same point.
Leave it as is. But it's frustrating when it happens.
It took me a while (days) to debug that there could be 2 multipart packages conflicting. If it was so difficult for me (that I'm supposed to know enough about FastAPI, I guess :shrug: ), I imagine how frustrating that could be for someone new.
To know the FastAPI version use:
python -c "import fastapi; print(fastapi.__version__)"
To know the Python version use:
python --version
Tom created an issue in the repo suggesting a name change: https://github.com/andrew-d/python-multipart/issues/16
But that will probably take some time to happen (if it happens).
@YKo20010 and I will be working on this issue!
I saw a lot of questions on StackOverflow related to this issue. Good one! :)
This is available in FastAPI version 0.60.2 :rocket: :tada:
Thanks for the work on this @chrisngyn, @YKo20010, @kx-chen ! :coffee: :cake:
Most helpful comment
@YKo20010 and I will be working on this issue!