tiangolo/fastapi · error · HTTPException

Item not found

Error message

Item not found

What it means

Raised (status 404) by GET /items/{item_id} after the token check passes, when item_id is not a key in the in-memory fake_db dict (which only contains 'foo' and 'bar'). This is the standard 'resource does not exist' response for the tutorial's ephemeral, process-local store. Because fake_db lives only in memory, it resets every server restart and never contains items added in a previous run unless re-added.

Solutions

  1. Use a known id: GET /items/foo or GET /items/bar.
  2. If you just created the item via POST /items/, GET it in the same server process before restarting.
  3. Persist fake_db to a real database or file for anything beyond a tutorial.

Example fix

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

Strategy: try-catch

Validate before calling

import httpx
KNOWN = {'foo', 'bar'}
def get_item(item_id: str):
    if item_id not in KNOWN:
        return None  # caller decides
    return httpx.get(f'http://localhost:8000/items/{item_id}', headers={'X-Token': 'coneofsilence'})

Type guard

def is_known_item(item_id: object) -> bool:
    return isinstance(item_id, str) and item_id in {'foo', 'bar'}

Try / catch

try:
    resp = httpx.get(url, headers=headers)
    resp.raise_for_status()
except httpx.HTTPStatusError as e:
    if e.response.status_code == 404:
        # item does not exist; handle gracefully
        ...

Prevention

When it happens

Trigger: Calling GET /items/baz (any id other than 'foo' or 'bar') with a valid X-Token. Also happens after a server restart if you expect an item POSTed in the previous process to still be there.

Common situations: Developer POSTs an item, restarts the dev server to pick up code changes, then GETs it and gets 404 because the in-memory dict was wiped. Or a typo in the path parameter.

Related errors


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

Appendix: source

Thrown at docs_src/app_testing/app_b_an_py310/main.py:27

    "foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"},
    "bar": {"id": "bar", "title": "Bar", "description": "The bartenders"},
}

app = FastAPI()


class Item(BaseModel):
    id: str
    title: str
    description: str | None = None


@app.get("/items/{item_id}", response_model=Item)
async def read_main(item_id: str, x_token: Annotated[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: Annotated[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)