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
- GET /items/plumbus or /items/gun.
- Confirm you are hitting the bigger-applications app, not the app_testing one (different seed sets).
- 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
- Remember the seed set here differs from other tutorials.
- Whitelist known ids before GET.
- Confirm which app you are calling.
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)