{"record":{"id":"bfc9962b922f5972","repo":"tiangolo/fastapi","slug":"item-not-found","errorCode":null,"errorMessage":"Item not found","messagePattern":"Item not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"error","filePath":"docs_src/app_testing/app_b_an_py310/main.py","lineNumber":27,"sourceCode":"    \"foo\": {\"id\": \"foo\", \"title\": \"Foo\", \"description\": \"There goes my hero\"},\n    \"bar\": {\"id\": \"bar\", \"title\": \"Bar\", \"description\": \"The bartenders\"},\n}\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    id: str\n    title: str\n    description: str | None = None\n\n\n@app.get(\"/items/{item_id}\", response_model=Item)\nasync def read_main(item_id: str, x_token: Annotated[str, Header()]):\n    if x_token != fake_secret_token:\n        raise HTTPException(status_code=400, detail=\"Invalid X-Token header\")\n    if item_id not in fake_db:\n        raise HTTPException(status_code=404, detail=\"Item not found\")\n    return fake_db[item_id]\n\n\n@app.post(\"/items/\")\nasync def create_item(item: Item, x_token: Annotated[str, Header()]) -> Item:\n    if x_token != fake_secret_token:\n        raise HTTPException(status_code=400, detail=\"Invalid X-Token header\")\n    if item.id in fake_db:\n        raise HTTPException(status_code=409, detail=\"Item already exists\")\n    fake_db[item.id] = item.model_dump()\n    return item\n","sourceCodeStart":9,"sourceCodeEnd":39,"githubUrl":"https://github.com/tiangolo/fastapi/blob/3e8d1526d83a90aaf7d6eb6dc682bf150f180b25/docs_src/app_testing/app_b_an_py310/main.py#L9-L39","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use a known id: GET /items/foo or GET /items/bar.","If you just created the item via POST /items/, GET it in the same server process before restarting.","Persist fake_db to a real database or file for anything beyond a tutorial."],"exampleFix":"// before\nGET /items/baz\n// after\nGET /items/foo","handlingStrategy":"try-catch","validationCode":"import httpx\nKNOWN = {'foo', 'bar'}\ndef get_item(item_id: str):\n    if item_id not in KNOWN:\n        return None  # caller decides\n    return httpx.get(f'http://localhost:8000/items/{item_id}', headers={'X-Token': 'coneofsilence'})","typeGuard":"def is_known_item(item_id: object) -> bool:\n    return isinstance(item_id, str) and item_id in {'foo', 'bar'}","tryCatchPattern":"try:\n    resp = httpx.get(url, headers=headers)\n    resp.raise_for_status()\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 404:\n        # item does not exist; handle gracefully\n        ...","preventionTips":["Treat the in-memory store as ephemeral; never assume cross-restart persistence.","GET an item in the same process that created it.","Whitelist known ids client-side before calling."],"tags":["fastapi","not-found","in-memory-store","httpexception","app-testing"],"backgroundTag":null,"analyzedSha":"3e8d1526d83a90aaf7d6eb6dc682bf150f180b25","analyzedAt":"2026-08-11T02:34:52.986Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}