tiangolo/fastapi · error · HTTPException
X-Token header invalid
Error message
X-Token header invalid
What it means
FastAPI returns HTTP 400 with detail "X-Token header invalid" when the `X-Token` request header does not equal the hard-coded expected value "fake-super-secret-token". The check lives in `verify_token`, registered as an application-wide dependency via `FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)])`, so it runs before every route (/items/ and /users/). It demonstrates global dependency-based API-key guarding.
Source
Thrown at docs_src/dependencies/tutorial012_an_py310.py:8
from typing import Annotated
from fastapi import Depends, FastAPI, Header, HTTPException
async def verify_token(x_token: Annotated[str, Header()]):
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
async def verify_key(x_key: Annotated[str, Header()]):
if x_key != "fake-super-secret-key":
raise HTTPException(status_code=400, detail="X-Key header invalid")
return x_key
app = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)])
@app.get("/items/")
async def read_items():
return [{"item": "Portal Gun"}, {"item": "Plumbus"}]
@app.get("/users/")
async def read_users():View on GitHub (pinned to 42a41db11f)
Solutions
- Send `X-Token: fake-super-secret-token` on every request.
- Load the expected token from an environment variable instead of hardcoding so rotation is possible.
- Return 401 instead of 400 for auth failures to follow HTTP semantics.
- Document required headers in the OpenAPI security scheme.
Example fix
# before
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
# after
import os
if x_token != os.environ["EXPECTED_TOKEN"]:
raise HTTPException(status_code=401, detail="Invalid X-Token") Defensive patterns
Strategy: validation
Validate before calling
TOKEN = "fake-super-secret-token"
headers = {"X-Token": TOKEN}
assert headers["X-Token"], "X-Token required"
client.get("/items/", headers=headers) Type guard
def has_valid_token(headers: dict) -> bool:
return headers.get("X-Token") == "fake-super-secret-token" Try / catch
r = client.get("/items/", headers=headers)
if r.status_code == 400 and r.json().get("detail") == "X-Token header invalid":
# refresh credentials; do not retry with the same header
... Prevention
- Inject required headers from a single client helper.
- Store tokens in config/env, not literals in code paths that ship.
- Treat header-invalid 400 as auth failure (consider 401 in your own APIs).
When it happens
Trigger: Any request (GET /items/ or GET /users/) missing `X-Token: fake-super-secret-token`, or sending a wrong value.
Common situations: Clients forgetting the header; sending the header with different casing of the value; sharing the wrong token; rotating the secret without notifying clients; proxy/gateway stripping custom headers.
Related errors
- X-Key header invalid
- X-Token header invalid
- X-Key header invalid
- Invalid X-Token header
- Invalid X-Token header
AI-assisted analysis of tiangolo/fastapi@42a41db11f (2026-08-04).
Data as JSON: /data/errors/cebdd7177513624a.json.
Report an issue: GitHub.