Main Ecosystems
HomePython CorePandas ReferenceNumPy ScientificFastAPI & PydanticDjango Enterprise
More Ecosystems
Environment & SetupRequests & HTTPAsyncIO ConcurrencyObject-Oriented OOPPyTorch Deep LearningScikit-Learn MLFlask FrameworkWeb ScrapingDatabase & ORMDevOps & Docker

ValidationError: value is not a valid dict in FastAPI & Pydantic

Verified FixPython 3.10+Pydantic 2.0+ / FastAPI 0.110+Silo: fastapi

Quick Fix / Solution Rapide

Ensure requests send valid JSON with header Content-Type: application/json matching the Pydantic schema model.

Root Cause Analysis

This error occurs when Python tries to validate incoming HTTP request data against a Pydantic model in FastAPI, but the parsed input is a string, list, or scalar instead of a valid key-value dictionary.

1. Pydantic Body Validation Protocol

In FastAPI and Pydantic v2, when a route endpoint declares a request body model item: ItemPayload, the framework expects the raw HTTP request body to be a valid JSON object (deserialized into a Python dict). If the incoming data is a plain string, integer, or array, Pydantic's core validator rejects the payload with ValidationError: Input should be a valid dictionary or instance to extract fields from.

2. Common Causes in API Clients

This error typically arises when: (1) an API client sends a JSON string double-encoded as a string literal, (2) the HTTP request header Content-Type is missing or set to text/plain rather than application/json, (3) client code passes a list of items [...] instead of a single object {...}, or (4) a query parameter is mistakenly configured as a body model.

3. Pydantic v1 vs Pydantic v2 Differences

In Pydantic v1, the error message was formatted as value is not a valid dict. In Pydantic v2, the message is Input should be a valid dictionary or instance to extract fields from. Both indicate that the schema expected a dictionary mapping but received an incompatible type.

4. Ensuring Clean API Ingestion

To fix this error, ensure the client serializes payloads as proper JSON dictionaries and use FastAPI's Body(...) or Query(...) annotations to distinguish body payloads from query parameters.

Reproduction Code (MCVE)

Example: Bug Reproduction
from pydantic import BaseModel, ValidationError

class ItemPayload(BaseModel):
    name: str
    price: float

# ValidationError: Input should be a valid dictionary or instance to extract fields from
raw_invalid_input = 'this is a raw string, not a dictionary'
ItemPayload.model_validate(raw_invalid_input)

Solution 1: Pass a Valid Key-Value Dictionary to Pydantic

Ensure incoming payloads are properly deserialized into Python dictionaries before invoking Pydantic validation.

Example: Recommended Solution
import json
from pydantic import BaseModel

class ItemPayload(BaseModel):
    name: str
    price: float

# Ensure payload is parsed as a valid dictionary
json_str = '{"name": "Wireless Mouse", "price": 29.99}'
dict_data = json.loads(json_str)

item = ItemPayload.model_validate(dict_data)
print(f'Validated successfully: {item.name} (${item.price})')

Solution 2: Use model_validate_json for Direct JSON String Parsing

In Pydantic v2, use model_validate_json() to parse and validate raw JSON strings directly with optimized C/Rust performance.

Example: Alternative Solution
from pydantic import BaseModel

class ItemPayload(BaseModel):
    name: str
    price: float

# Direct parsing from raw JSON string
raw_json = '{"name": "Mechanical Keyboard", "price": 129.50}'
item = ItemPayload.model_validate_json(raw_json)
print(f'Validated via model_validate_json: {item.name} (${item.price})')

A common mistake when using FastAPI is forgetting the Content-Type: application/json header in curl or Postman requests, causing FastAPI to misinterpret the body. Contrast ValidationError (semantic schema violation) with json.decoder.JSONDecodeError (malformed JSON syntax like trailing commas). When expecting an array of items, define the endpoint parameter as items: list[ItemPayload] rather than ItemPayload alone. In Pydantic v2, avoid legacy v1 methods like parse_obj() and use model_validate() instead.