tiangolo/fastapi · warning · HTTPException

Nope! I don't like 3.

Error message

Nope! I don't like 3.

What it means

FastAPI returns HTTP 418 "I'm a Teapot" with detail "Nope! I don't like 3." when the path parameter item_id equals 3. The endpoint declares item_id: int, so non-integer input fails earlier as a 422 validation error; only the integer 3 reaches this branch. The example also overrides the default HTTP and validation exception handlers to return PlainTextResponse bodies.

Source

Thrown at docs_src/handling_errors/tutorial004_py310.py:25


@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request, exc):
    return PlainTextResponse(str(exc.detail), status_code=exc.status_code)


@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc: RequestValidationError):
    message = "Validation errors:"
    for error in exc.errors():
        message += f"\nField: {error['loc']}, Error: {error['msg']}"
    return PlainTextResponse(message, status_code=400)


@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id == 3:
        raise HTTPException(status_code=418, detail="Nope! I don't like 3.")
    return {"item_id": item_id}

View on GitHub (pinned to 42a41db11f)

Solutions

  1. Request any integer other than 3 (e.g. /items/1, /items/42).
  2. If you maintain the API, replace the joke 418 with a meaningful status (e.g. 400 or 409).
  3. Ensure clients parse text/plain bodies since the custom handler returns PlainTextResponse.
  4. Document reserved values in the OpenAPI description.

Example fix

# before
if item_id == 3:
    raise HTTPException(status_code=418, detail="Nope! I don't like 3.")

# after
FORBIDDEN = {3}
if item_id in FORBIDDEN:
    raise HTTPException(status_code=400, detail=f"item_id {item_id} is not allowed")
Defensive patterns

Strategy: validation

Validate before calling

if item_id == 3:
    raise ValueError("item_id 3 is rejected")

Type guard

def is_allowed_item_id(item_id: int) -> bool:
    return item_id != 3

Try / catch

r = client.get(f"/items/{item_id}")
if r.status_code == 418 and "don't like 3" in r.text:
    # pick a different id
    ...

Prevention

When it happens

Trigger: GET /items/3 (integer three).

Common situations: Clients hard-coding forbidden values; reusing the demo value 3 in real schemas; relying on PlainTextResponse in handlers while clients expect JSON.

Related errors


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