tiangolo/fastapi · error · HTTPException
Incorrect username or password
Error message
Incorrect username or password
What it means
Default-parameter twin of error 44: the `/token` handler raises HTTP 400 'Incorrect username or password' when `fake_users_db.get(form_data.username)` is None. Message is shared with the wrong-password branch (line 81) to prevent user enumeration.
Source
Thrown at docs_src/security/tutorial003_py310.py:77
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Not authenticated",
headers={"WWW-Authenticate": "Bearer"},
)
return user
async def get_current_active_user(current_user: User = Depends(get_current_user)):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
return current_user
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user_dict = fake_users_db.get(form_data.username)
if not user_dict:
raise HTTPException(status_code=400, detail="Incorrect username or password")
user = UserInDB(**user_dict)
hashed_password = fake_hash_password(form_data.password)
if not hashed_password == user.hashed_password:
raise HTTPException(status_code=400, detail="Incorrect username or password")
return {"access_token": user.username, "token_type": "bearer"}
@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_active_user)):
return current_user
View on GitHub (pinned to 42a41db11f)
Solutions
- POST as `application/x-www-form-urlencoded` per the OAuth2 password grant.
- Use a username that exists in the store.
- Remember the same message covers a wrong password (line 81).
Example fix
# before curl -X POST http://localhost:8000/token -d 'username=ghost&password=x' # after curl -X POST http://localhost:8000/token -d 'username=johndoe&password=secret'
Defensive patterns
Strategy: try-catch
Validate before calling
def is_form_login(username: str, password: str) -> bool:
return bool(username) and bool(password)
# POST with Content-Type: application/x-www-form-urlencoded when True Type guard
def is_credentials_error(resp) -> bool:
return getattr(resp, 'status_code', None) in (400, 401) and \
resp.json().get('detail') == 'Incorrect username or password' Try / catch
try:
tok = client.post('/token', data={'username': u, 'password': p})
tok.raise_for_status()
except httpx.HTTPStatusError as e:
if e.response.json().get('detail') == 'Incorrect username or password':
show_user_friendly_login_error()
raise Prevention
- Use form encoding for /token, never JSON.
- Keep the generic message; do not help attackers enumerate.
- Rate-limit login attempts.
When it happens
Trigger: `POST /token` form-encoded with `username=<unknown>`. Branch `if not user_dict:` at line 76.
Common situations: Username typo; JSON body sent instead of form data so `form_data.username` is empty; user not provisioned; wrong environment.
Related errors
- Incorrect username or password
- Incorrect username or password
- Incorrect username or password
- Incorrect username or password
- Incorrect username or password
AI-assisted analysis of tiangolo/fastapi@42a41db11f (2026-08-04).
Data as JSON: /data/errors/3fc278352c08ca17.json.
Report an issue: GitHub.