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

  1. Ensure the YAML body supplies all required `Item` fields (`name: str`, `tags: list[str]`) before sending.
  2. If you are on Pydantic v1, drop `include_url=False` or upgrade to Pydantic v2 (`pip install -U pydantic`).
  3. Build the body from a validated model instance (`yaml.dump(item.model_dump())`) instead of hand-writing YAML.
  4. 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

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


AI-assisted analysis of tiangolo/fastapi@42a41db11f (2026-08-04). Data as JSON: /data/errors/47b459a384d476fe.json. Report an issue: GitHub.