{"record":{"id":"cebdd7177513624a","repo":"tiangolo/fastapi","slug":"x-token-header-invalid-cebdd7","errorCode":null,"errorMessage":"X-Token header invalid","messagePattern":"X-Token header invalid","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"docs_src/dependencies/tutorial012_an_py310.py","lineNumber":8,"sourceCode":"from typing import Annotated\n\nfrom fastapi import Depends, FastAPI, Header, HTTPException\n\n\nasync def verify_token(x_token: Annotated[str, Header()]):\n    if x_token != \"fake-super-secret-token\":\n        raise HTTPException(status_code=400, detail=\"X-Token header invalid\")\n\n\nasync def verify_key(x_key: Annotated[str, Header()]):\n    if x_key != \"fake-super-secret-key\":\n        raise HTTPException(status_code=400, detail=\"X-Key header invalid\")\n    return x_key\n\n\napp = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)])\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    return [{\"item\": \"Portal Gun\"}, {\"item\": \"Plumbus\"}]\n\n\n@app.get(\"/users/\")\nasync def read_users():","sourceCodeStart":1,"sourceCodeEnd":26,"githubUrl":"https://github.com/tiangolo/fastapi/blob/3e8d1526d83a90aaf7d6eb6dc682bf150f180b25/docs_src/dependencies/tutorial012_an_py310.py#L1-L26","documentation":"HTTPException (400) raised by the global dependency verify_token, registered on the FastAPI app via dependencies=[Depends(verify_token), ...]. It reads the X-Token header and compares to a hard-coded secret 'fake-super-secret-token'. Because it is an app-level dependency, EVERY route (e.g. /items/ and /users/) requires the header. FastAPI runs these before the path operation, so a bad/missing token fails every request with 400.","triggerScenarios":"Any request to /items/ or /users/ (or any route on this app) without header 'X-Token: fake-super-secret-token', or with a wrong value. Missing header triggers FastAPI's own 422 (missing required header) before this 400; a present-but-wrong value triggers this 400.","commonSituations":"Global API-key/header gateways. Developers hit this when their client omits the X-Token header, sends it under a different name (case or hyphenation), or rotates the secret on the server but not the client.","solutions":["Send header X-Token: fake-super-secret-token (exact value) on every request.","Double-check header name casing/hyphenation — FastAPI maps x_token parameter to the 'X-Token' header; 'X-Token' and 'x-token' are equivalent but other spellings are not.","If the token is real, source it from configuration/env rather than hard-coding, and ensure the client uses the same source."],"exampleFix":"// before\ncurl http://localhost:8000/items/\n// after\ncurl -H 'X-Token: fake-super-secret-token' -H 'X-Key: fake-super-secret-key' http://localhost:8000/items/","handlingStrategy":"validation","validationCode":"headers = {'X-Token': os.environ.get('X_TOKEN', 'fake-super-secret-token'), 'X-Key': 'fake-super-secret-key'}\nassert headers['X-Token'], 'X-Token required'","typeGuard":"def has_valid_x_token(headers: dict) -> bool:\n    return headers.get('X-Token') == 'fake-super-secret-token'","tryCatchPattern":"resp = requests.get('http://localhost:8000/items/', headers=headers)\nif resp.status_code == 400 and 'X-Token' in resp.text:\n    print('bad/missing X-Token')","preventionTips":["Send both X-Token and X-Key on every request.","Source secrets from env/config, not literals.","Verify header name mapping (x_token -> X-Token)."],"tags":["fastapi","http-400","headers","authentication","global-dependency"],"backgroundTag":null,"analyzedSha":"3e8d1526d83a90aaf7d6eb6dc682bf150f180b25","analyzedAt":"2026-08-11T02:34:52.986Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}