tiangolo/fastapi · error · HTTPException

Item not found

Error message

Item not found

What it means

Raised (404) by GET /items/{item_id} on the items router when item_id is not in fake_items_db, which is seeded with only 'plumbus' and 'gun'. The router already declares responses={404: {...}} so this is the documented not-found path. Note the X-Token dependency has already passed by this point.

Solutions

  1. GET /items/plumbus or /items/gun.
  2. Confirm you are hitting the bigger-applications app, not the app_testing one (different seed sets).
  3. Add the missing id to fake_items_db if testing a read path.

Example fix

// before
GET /items/foo
// after
GET /items/plumbus
Defensive patterns

Strategy: try-catch

Validate before calling

import httpx
KNOWN = {'plumbus', 'gun'}
item_id = 'plumbus'
if item_id in KNOWN:
    resp = httpx.get(f'http://localhost:8000/items/{item_id}', headers={'X-Token': 'fake-super-secret-token'})

Type guard

def is_known_router_item(item_id: object) -> bool:
    return isinstance(item_id, str) and item_id in {'plumbus', 'gun'}

Try / catch

try:
    resp = httpx.get(url, headers=headers)
    resp.raise_for_status()
except httpx.HTTPStatusError as e:
    if e.response.status_code == 404:
        ...

Prevention

When it happens

Trigger: GET /items/plumbus or /items/gun succeed; any other id (e.g. /items/foo) with a valid X-Token yields this 404.

Common situations: Confusing this router's seed data ({plumbus, gun}) with the app_testing seed ({foo, bar}); typos; expecting an item created elsewhere.

Related errors


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

Appendix: source

Thrown at docs_src/bigger_applications/app_an_py310/routers/items.py:24

    prefix="/items",
    tags=["items"],
    dependencies=[Depends(get_token_header)],
    responses={404: {"description": "Not found"}},
)


fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}


@router.get("/")
async def read_items():
    return fake_items_db


@router.get("/{item_id}")
async def read_item(item_id: str):
    if item_id not in fake_items_db:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"name": fake_items_db[item_id]["name"], "item_id": item_id}


@router.put(
    "/{item_id}",
    tags=["custom"],
    responses={403: {"description": "Operation forbidden"}},
)
async def update_item(item_id: str):
    if item_id != "plumbus":
        raise HTTPException(
            status_code=403, detail="You can only update the item: plumbus"
        )
    return {"item_id": item_id, "name": "The great Plumbus"}

View on GitHub (pinned to 3e8d1526d8)