tiangolo/fastapi · error · HTTPException

Item already exists

Error message

Item already exists

What it means

POST /items/ duplicate-id check (409) in the legacy-style file: raises when item.id is already a key in fake_db. Pre-seeded ids 'foo' and 'bar' always conflict; any id POSTed twice in one process conflicts on the second call.

Solutions

  1. Use a fresh unique id per create (uuid4).
  2. Handle 409 as idempotent success when the stored item matches.
  3. Switch to PUT for upsert behavior.

Example fix

// before
POST /items/  {"id":"foo", ...}
// after
POST /items/  {"id": str(uuid4()), ...}
Defensive patterns

Strategy: try-catch

Validate before calling

import uuid, httpx
def create(item: dict):
    item = {**item, 'id': str(uuid.uuid4())}
    return httpx.post('http://localhost:8000/items/', json=item, headers={'X-Token': 'coneofsilence'})

Type guard

def is_unique_id(proposed: str, existing: set[str]) -> bool:
    return proposed not in existing

Try / catch

try:
    resp = httpx.post(url, json=item, headers=headers)
    resp.raise_for_status()
except httpx.HTTPStatusError as e:
    if e.response.status_code == 409:
        ...

Prevention

When it happens

Trigger: POST /items/ with id 'foo' or 'bar', or POSTing the same id twice.

Common situations: Retried POSTs after a client timeout; fixed/test ids that collide with seed data.

Related errors


AI-assisted analysis of tiangolo/fastapi@3e8d1526d8 (2026-08-11). Data as JSON: /api/errors/f2bd8c6e63b061ed. Report an issue: GitHub.

Appendix: source

Thrown at docs_src/app_testing/app_b_py310/main.py:34

    title: str
    description: str | None = None


@app.get("/items/{item_id}", response_model=Item)
async def read_main(item_id: str, x_token: str = Header()):
    if x_token != fake_secret_token:
        raise HTTPException(status_code=400, detail="Invalid X-Token header")
    if item_id not in fake_db:
        raise HTTPException(status_code=404, detail="Item not found")
    return fake_db[item_id]


@app.post("/items/")
async def create_item(item: Item, x_token: str = Header()) -> Item:
    if x_token != fake_secret_token:
        raise HTTPException(status_code=400, detail="Invalid X-Token header")
    if item.id in fake_db:
        raise HTTPException(status_code=409, detail="Item already exists")
    fake_db[item.id] = item.model_dump()
    return item

View on GitHub (pinned to 3e8d1526d8)