tiangolo/fastapi · error · HTTPException

Item not found, there's only a plumbus here

Error message

Item not found, there's only a plumbus here

What it means

FastAPI returns HTTP 404 with the whimsical detail "Item not found, there's only a plumbus here" when `item_id` is anything other than "plumbus" or "portal-gun". The "portal-gun" branch raises InternalError instead (handled by the yield dependency), so this 404 only fires for genuinely unknown ids. It demonstrates custom 404 messaging combined with yield-dependency exception swallowing.

Source

Thrown at docs_src/dependencies/tutorial008c_an_py310.py:26

class InternalError(Exception):
    pass


def get_username():
    try:
        yield "Rick"
    except InternalError:
        print("Oops, we didn't raise again, Britney 😱")


@app.get("/items/{item_id}")
def get_item(item_id: str, username: Annotated[str, Depends(get_username)]):
    if item_id == "portal-gun":
        raise InternalError(
            f"The portal gun is too dangerous to be owned by {username}"
        )
    if item_id != "plumbus":
        raise HTTPException(
            status_code=404, detail="Item not found, there's only a plumbus here"
        )
    return item_id

View on GitHub (pinned to 42a41db11f)

Solutions

  1. Request GET /items/plumbus (the only valid non-portal-gun id).
  2. If extending the API, enumerate allowed ids and document them in the OpenAPI summary.
  3. Normalize custom 404 detail strings across endpoints for consistency.
  4. Add a test asserting both the portal-gun InternalError path and the generic 404 path.

Example fix

# before
if item_id != "plumbus":
    raise HTTPException(status_code=404, detail="Item not found, there's only a plumbus here")

# after
ALLOWED = {"plumbus"}
if item_id not in ALLOWED:
    raise HTTPException(status_code=404, detail=f"Item '{item_id}' not found")
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED = {"plumbus", "portal-gun"}
if item_id not in ALLOWED:
    raise ValueError(f"Item '{item_id}' not supported; only {ALLOWED}")

Type guard

def is_known_item(item_id: str) -> bool:
    return item_id in {"plumbus", "portal-gun"}

Try / catch

r = client.get(f"/items/{item_id}")
if r.status_code == 404:
    # inform the user that only plumbus/portal-gun exist
    ...

Prevention

When it happens

Trigger: GET /items/<anything-except-plumbus-or-portal-gun> (e.g. /items/flerb).

Common situations: Clients probing for resources that were never modeled; renaming the allowed id set without updating clients; tutorials copied with a different allowed-item list.

Related errors


AI-assisted analysis of tiangolo/fastapi@42a41db11f (2026-08-04). Data as JSON: /data/errors/c1ba9d0c33c8a518.json. Report an issue: GitHub.