tiangolo/fastapi · error · HTTPException

Invalid X-Token header

Error message

Invalid X-Token header

What it means

This HTTPException is raised by the GET /items/{item_id} handler in the app-testing example when the incoming X-Token request header does not equal the hardcoded secret token ("coneofsilence"). FastAPI uses HTTPException to short-circuit the request and return a structured JSON error response with HTTP status 400 instead of running the rest of the handler. It is a simple bearer-style guard meant to demonstrate authentication on a protected read endpoint.

Source

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

fake_db = {
    "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 42a41db11f)

Solutions

  1. Send the header X-Token: coneofsilence on every GET /items/{item_id} request.
  2. If using TestClient, pass headers={"X-Token": "coneofsilence"} in the call.
  3. Replace the hardcoded token with a value loaded from settings/env so client and server agree.
  4. Confirm the header name casing/underscore: FastAPI maps x_token to the X-Token header.

Example fix

# before
client.get("/items/foo")
# after
client.get("/items/foo", headers={"X-Token": "coneofsilence"})
Defensive patterns

Strategy: validation

Validate before calling

# Validate the token is present and correct before sending
EXPECTED_TOKEN = "coneofsilence"
assert EXPECTED_TOKEN, "X-Token not configured"
headers = {"X-Token": EXPECTED_TOKEN} if EXPECTED_TOKEN else {}

Type guard

def has_valid_token(token: str | None) -> bool:
    return token is not None and token == "coneofsilence"

Prevention

When it happens

Trigger: A GET /items/{item_id} request where the X-Token header is absent, empty, or any value other than "coneofsilence" (e.g. curl http://host/items/foo without -H "X-Token: coneofsilence").

Common situations: Test clients (httpx/TestClient) that forget to attach the header; frontend code that drops headers on a refresh; copying an example with a placeholder token; deploying with a token that differs from the client's configured value.

Related errors


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