tiangolo/fastapi · error · ValueError
Expected UploadFile, received
Error message
Expected UploadFile, received: {type(__input_value)} What it means
ValueError raised by UploadFile._validate, the pydantic validator registered for the UploadFile type via with_info_plain_validator_function. The validator (datastructures.py:135) requires the incoming value to be an instance of starlette UploadFile; anything else (str, bytes, dict, a file path, a SpooledTemporaryFile, etc.) is rejected because FastAPI/Starlette can only wrap a real uploaded file handle. Pydantic surfaces this ValueError as a request validation error.
Solutions
- Send the data as a real multipart file upload with the correct field name (requests files={...}, curl -F, httpx files=).
- Annotate the parameter as bytes or Annotated[bytes, File()] if you want raw bytes, or as a pydantic model / Form field if the input is not a file.
- In tests, open the file and pass the file object: files={'file': ('x.bin', open(path,'rb'), 'application/octet-stream')}.
- Verify the request Content-Type is multipart/form-data and the field name matches the parameter name.
Example fix
// before
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
return {"filename": file.filename}
# client sent JSON: {"file": "report.pdf"} -> ValueError
// after
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
return {"filename": file.filename}
# client sends multipart:
# httpx.post(url, files={"file": ("report.pdf", open("report.pdf","rb"))}) Defensive patterns
Strategy: type-guard
Validate before calling
# Ensure a real file object is used before constructing the request
import os
from starlette.datastructures import UploadFile
def make_files(name: str, path: str):
f = open(path, "rb")
assert isinstance(f, (object,)) and os.path.exists(path)
return {name: (os.path.basename(path), f, "application/octet-stream")} Type guard
from starlette.datastructures import UploadFile
def is_uploadable(value) -> bool:
return isinstance(value, UploadFile) Try / catch
from fastapi import HTTPException
from starlette.datastructures import UploadFile
async def take_file(value):
if not isinstance(value, UploadFile):
raise HTTPException(status_code=400, detail="a file upload is required")
return await value.read() Prevention
- Always send file fields as multipart file parts, never as JSON strings.
- Match the multipart field name to the endpoint parameter name.
- In tests, open real file objects with the correct (filename, file, content_type) tuple.
- Use Annotated[bytes, File()] when you want raw bytes instead of a file wrapper.
When it happens
Trigger: Declaring a path-operation parameter as UploadFile (or Annotated[UploadFile, File()]) but the request did not send a file part — e.g. the client sent a JSON string, plain bytes, a form field, or the test/client passed a non-file object. Also triggered by directly constructing/validating an UploadFile-typed model with a non-file input.
Common situations: Forgetting to upload an actual file (sending the filename string instead); test code that passes bytes to an UploadFile field instead of a file-like object; a proxy/middleware that replaced the upload with its raw contents; mismatched field name between client and endpoint.
Related errors
- {"errors": exc.errors(), "body": body.decode()}
- {"errors": exc.errors(), "body": body.decode()}
- validation error(s)
- Cannot set both 'data' and 'raw_data' on the same…
- Code block (lines - ) has different language than the…
AI-assisted analysis of tiangolo/fastapi@3e8d1526d8 (2026-08-11).
Data as JSON: /api/errors/8693ca626d9c6114.
Report an issue: GitHub.
Appendix: source
Thrown at fastapi/datastructures.py:135
Any next read or write will be done from that position.
To be awaitable, compatible with async, this is run in threadpool.
"""
return await super().seek(offset)
async def close(self) -> None:
"""
Close the file.
To be awaitable, compatible with async, this is run in threadpool.
"""
return await super().close()
@classmethod
def _validate(cls, __input_value: Any, _: Any) -> "UploadFile":
if not isinstance(__input_value, StarletteUploadFile):
raise ValueError(f"Expected UploadFile, received: {type(__input_value)}")
return cast(UploadFile, __input_value)
@classmethod
def __get_pydantic_json_schema__(
cls, core_schema: Mapping[str, Any], handler: GetJsonSchemaHandler
) -> dict[str, Any]:
return {"type": "string", "contentMediaType": "application/octet-stream"}
@classmethod
def __get_pydantic_core_schema__(
cls, source: type[Any], handler: Callable[[Any], Mapping[str, Any]]
) -> Mapping[str, Any]:
from ._compat.v2 import with_info_plain_validator_function
return with_info_plain_validator_function(cls._validate)
class DefaultPlaceholder:View on GitHub (pinned to 3e8d1526d8)