Skip to content

FastAPI Form Data File Fix

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about FastAPI Form Data File Fix. We cover key concepts, practical examples, and best practices.

The Problem

A form that submits text fields (name, email) alongside a file (avatar) requires parsing multipart form data. FastAPI handles this with Form and File but mixing them incorrectly causes errors.

Quick Fix

Wrong — using JSON body for file uploads

from fastapi import FastAPI
from pydantic import BaseModel

class UserCreate(BaseModel):
    name: str
    email: str
    avatar: str  # Can't send files as JSON string

@app.post("/users")
async def create_user(user: UserCreate):
    ...

Output: Can't upload binary file data via JSON. Client must base64-encode, which increases size by 33%.

Correct — Form + File together

from fastapi import FastAPI, File, UploadFile, Form

app = FastAPI()

@app.post("/users")
async def create_user(
    name: str = Form(...),
    email: str = Form(...),
    avatar: UploadFile = File(...),
):
    contents = await avatar.read()
    # Save to disk or cloud storage
    avatar_url = await save_avatar(avatar.filename, contents)

    user = await db.execute(
        "INSERT INTO users (name, email, avatar_url) VALUES (?, ?, ?)",
        (name, email, avatar_url),
    )

    return {"id": user.id, "name": name, "email": email, "avatar_url": avatar_url}

Output: Client sends multipart/form-data with text fields and binary file. All parsed correctly.

Multiple files with form fields

from typing import List

@app.post("/gallery")
async def upload_gallery(
    title: str = Form(...),
    description: str = Form(...),
    images: List[UploadFile] = File(...),
):
    urls = []
    for image in images:
        url = await save_image(image)
        urls.append(url)
    return {"title": title, "images": urls}

Optional file with form data

@app.post("/profile")
async def update_profile(
    display_name: str = Form(...),
    bio: str = Form(default=""),
    avatar: UploadFile = File(None),  # Optional
):
    avatar_url = None
    if avatar and avatar.filename:
        avatar_url = await save_avatar(avatar)

    return {"display_name": display_name, "avatar_url": avatar_url}

Testing form + file endpoints

from fastapi.testclient import TestClient

def test_create_user():
    client = TestClient(app)
    response = client.post(
        "/users",
        data={"name": "John", "email": "john@example.com"},
        files={"avatar": ("avatar.jpg", b"image_data", "image/jpeg")},
    )
    assert response.status_code == 200

Prevention

  • Use Form(...) for text fields and File(...) or UploadFile for file fields.
  • Declare all form parameters as function arguments — don't mix with Pydantic models for form data.
  • Use File(None) for optional file uploads.

Common Mistakes with form data file

  1. Using return to exit a function early instead of wrapping a pure value in the monad
  2. Mixing let bindings with <- bindings in do notation, producing type errors
  3. Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors

These mistakes appear frequently in real-world FASTAPI code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### Why can't I use a Pydantic model with Form data?

FastAPI doesn't support Pydantic models for form data. Use individual Form() parameters. Use Pydantic for JSON request bodies.

What is the difference between File and UploadFile?

File(...) returns bytes (in memory). UploadFile provides a file-like interface with streaming for larger files.

Can I mix JSON and file uploads?

No. A request can't have both application/json and multipart/form-data. Use form data for text fields + files, or base64-encode the file in JSON.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro