{"record":{"id":"21ab48034f47e139","repo":"tiangolo/fastapi","slug":"you-can-only-update-the-item-plumbus","errorCode":null,"errorMessage":"You can only update the item: plumbus","messagePattern":"You can only update the item: plumbus","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"docs_src/bigger_applications/app_an_py310/routers/items.py","lineNumber":35,"sourceCode":"async def read_items():\n    return fake_items_db\n\n\n@router.get(\"/{item_id}\")\nasync def read_item(item_id: str):\n    if item_id not in fake_items_db:\n        raise HTTPException(status_code=404, detail=\"Item not found\")\n    return {\"name\": fake_items_db[item_id][\"name\"], \"item_id\": item_id}\n\n\n@router.put(\n    \"/{item_id}\",\n    tags=[\"custom\"],\n    responses={403: {\"description\": \"Operation forbidden\"}},\n)\nasync def update_item(item_id: str):\n    if item_id != \"plumbus\":\n        raise HTTPException(\n            status_code=403, detail=\"You can only update the item: plumbus\"\n        )\n    return {\"item_id\": item_id, \"name\": \"The great Plumbus\"}\n","sourceCodeStart":17,"sourceCodeEnd":39,"githubUrl":"https://github.com/tiangolo/fastapi/blob/3e8d1526d83a90aaf7d6eb6dc682bf150f180b25/docs_src/bigger_applications/app_an_py310/routers/items.py#L17-L39","documentation":"Raised (403) by PUT /items/{item_id} when item_id is not exactly 'plumbus'. This is a hard-coded business rule in the demo: only the plumbus item is mutable. The route declares responses={403: {...}} documenting it. The X-Token dependency has already run, so this is an authorization/semantics error, not an auth error.","triggerScenarios":"PUT /items/gun or PUT /items/<anything-not-plumbus> with a valid token. Even though 'gun' exists for GET, it is not writable.","commonSituations":"Assuming all readable items are writable; automating PUTs across all known ids; copy-pasting a PUT template with a fixed id.","solutions":["Only PUT /items/plumbus.","If broader mutability is needed, remove the hard-coded check and implement per-item ownership rules.","Document the writable set in the API contract so clients do not attempt others."],"exampleFix":"// before\nPUT /items/gun\n// after\nPUT /items/plumbus","handlingStrategy":"validation","validationCode":"import httpx\nWRITABLE = {'plumbus'}\ndef update(item_id: str):\n    if item_id not in WRITABLE:\n        raise ValueError(f'{item_id} is not writable')\n    return httpx.put(f'http://localhost:8000/items/{item_id}', headers={'X-Token': 'fake-super-secret-token'})","typeGuard":"def is_writable_item(item_id: object) -> bool:\n    return isinstance(item_id, str) and item_id == 'plumbus'","tryCatchPattern":null,"preventionTips":["Maintain a client-side set of writable ids.","Do not assume readability implies writability.","Document the writable contract for API consumers."],"tags":["fastapi","forbidden","business-rule","httpexception","bigger-applications"],"backgroundTag":null,"analyzedSha":"3e8d1526d83a90aaf7d6eb6dc682bf150f180b25","analyzedAt":"2026-08-11T02:34:52.986Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}