tiangolo/fastapi · error · HTTPException
e.errors(include_url=False)
Error message
e.errors(include_url=False)
What it means
This line fires when a YAML request body fails Pydantic validation against the `Item` model. `ValidationError.errors(include_url=False)` returns a list of per-field error dicts (with the Pydantic docs URL stripped) that FastAPI serializes into the 422 response `detail`. The `include_url` keyword is Pydantic v2 only; on Pydantic v1 this exact call raises `TypeError: errors() got an unexpected keyword argument 'include_url'`.
Source
Thrown at docs_src/path_operation_advanced_configuration/tutorial007_py310.py:31
@app.post(
"/items/",
openapi_extra={
"requestBody": {
"content": {"application/x-yaml": {"schema": Item.model_json_schema()}},
"required": True,
},
},
)
async def create_item(request: Request):
raw_body = await request.body()
try:
data = yaml.safe_load(raw_body)
except yaml.YAMLError:
raise HTTPException(status_code=422, detail="Invalid YAML")
try:
item = Item.model_validate(data)
except ValidationError as e:
raise HTTPException(status_code=422, detail=e.errors(include_url=False))
return item
View on GitHub (pinned to 42a41db11f)
Solutions
- Ensure the YAML body supplies all required `Item` fields (`name: str`, `tags: list[str]`) before sending.
- If you are on Pydantic v1, drop `include_url=False` or upgrade to Pydantic v2 (`pip install -U pydantic`).
- Build the body from a validated model instance (`yaml.dump(item.model_dump())`) instead of hand-writing YAML.
- Return a simpler `detail` (e.g. `detail=str(e)`) if you do not want the full structured error list.
Example fix
# before raise HTTPException(status_code=422, detail=e.errors(include_url=False)) # after (Pydantic v1 compatible) raise HTTPException(status_code=422, detail=e.errors())
Defensive patterns
Strategy: validation
Validate before calling
import yaml
ALLOWED = {"name": str, "tags": list}
def safe_yaml_payload(raw: bytes) -> dict:
data = yaml.safe_load(raw) or {}
assert isinstance(data, dict), "YAML must parse to a mapping"
for k, t in ALLOWED.items():
assert isinstance(data.get(k), t), f"{k} must be {t.__name__}"
assert all(isinstance(x, str) for x in data["tags"]), "tags must be list[str]"
return data Type guard
def is_item_dict(data: object) -> bool:
return (isinstance(data, dict)
and isinstance(data.get("name"), str)
and isinstance(data.get("tags"), list)
and all(isinstance(t, str) for t in data["tags"])) Try / catch
try:
resp = client.post("/items/", content=yaml.dump(payload),
headers={"content-type": "application/x-yaml"})
resp.raise_for_status()
except httpx.HTTPStatusError as e:
if e.response.status_code == 422:
log.error("validation errors: %s", e.response.json()["detail"])
raise Prevention
- Generate the YAML body from a validated model instance, not by hand.
- Pin Pydantic to v2 when using `include_url=False`.
- Always send `Content-Type: application/x-yaml` so the custom parser runs.
When it happens
Trigger: `POST /items/` with `Content-Type: application/x-yaml` and a body missing the required `tags` field, with `tags` set to a non-list, or with valid YAML that parses to `None`/wrong types.
Common situations: Migrating Pydantic v1 -> v2 (the kwarg did not exist in v1); clients sending malformed YAML or JSON-as-YAML; forgetting the `application/x-yaml` content type so the custom `request.body()` parse path is taken; Pydantic version pin mismatch between dev and CI.
Related errors
- {"errors": exc.errors(), "body": body.decode()}
- {"errors": exc.errors(), "body": body.decode()}
- Invalid YAML
- Invalid ID format, it must start with "isbn-" or "imdb-"
- Expected UploadFile, received: {type(__input_value)}
AI-assisted analysis of tiangolo/fastapi@42a41db11f (2026-08-04).
Data as JSON: /data/errors/47b459a384d476fe.json.
Report an issue: GitHub.