{"record":{"id":"df3a19588dd4e1c0","repo":"tiangolo/fastapi","slug":"inactive-user-df3a19","errorCode":null,"errorMessage":"Inactive user","messagePattern":"Inactive user","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"docs_src/security/tutorial003_py310.py","lineNumber":69,"sourceCode":"    # Check the next version\n    user = get_user(fake_users_db, token)\n    return user\n\n\nasync def get_current_user(token: str = Depends(oauth2_scheme)):\n    user = fake_decode_token(token)\n    if not user:\n        raise HTTPException(\n            status_code=status.HTTP_401_UNAUTHORIZED,\n            detail=\"Not authenticated\",\n            headers={\"WWW-Authenticate\": \"Bearer\"},\n        )\n    return user\n\n\nasync def get_current_active_user(current_user: User = Depends(get_current_user)):\n    if current_user.disabled:\n        raise HTTPException(status_code=400, detail=\"Inactive user\")\n    return current_user\n\n\n@app.post(\"/token\")\nasync def login(form_data: OAuth2PasswordRequestForm = Depends()):\n    user_dict = fake_users_db.get(form_data.username)\n    if not user_dict:\n        raise HTTPException(status_code=400, detail=\"Incorrect username or password\")\n    user = UserInDB(**user_dict)\n    hashed_password = fake_hash_password(form_data.password)\n    if not hashed_password == user.hashed_password:\n        raise HTTPException(status_code=400, detail=\"Incorrect username or password\")\n\n    return {\"access_token\": user.username, \"token_type\": \"bearer\"}\n\n\n@app.get(\"/users/me\")\nasync def read_users_me(current_user: User = Depends(get_current_active_user)):","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/tiangolo/fastapi/blob/3e8d1526d83a90aaf7d6eb6dc682bf150f180b25/docs_src/security/tutorial003_py310.py#L51-L87","documentation":"Same disabled-account gate as error 40, but in the legacy dependency-injection syntax (current_user: User = Depends(...) instead of Annotated[User, Depends(...)]). After get_current_user resolves the token to a valid user, line 68 rejects disabled users with HTTP 400 'Inactive user'. Functionally identical to error 40; only the DI style differs.","triggerScenarios":"GET /users/me (or any route depending on get_current_active_user) with a token resolving to a user whose disabled flag is True — e.g. token 'alice' because fake_decode_token uses the token as the username key.","commonSituations":"Using the seeded disabled 'alice' fixture; admin-suspended accounts; users modelled as disabled until email verification.","solutions":["Use an active user (disabled=False), e.g. 'johndoe'.","Flip disabled to False in fake_users_db for the account and re-send the request.","Migrate the raise to 403 Forbidden for disabled-but-authenticated users."],"exampleFix":"// before\nif current_user.disabled:\n    raise HTTPException(status_code=400, detail=\"Inactive user\")\n\n// after\nif current_user.disabled:\n    raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=\"Inactive user\")","handlingStrategy":"try-catch","validationCode":"DISABLED_USERS = {\"alice\"}\ndef looks_active(token_or_username: str) -> bool:\n    return token_or_username not in DISABLED_USERS","typeGuard":"from typing import TypeGuard\ndef is_active_user(u: dict) -> TypeGuard[dict]:\n    return not u.get(\"disabled\", False)","tryCatchPattern":"import httpx\ntry:\n    r = httpx.get(\"/users/me\", headers={\"Authorization\": f\"Bearer {token}\"})\n    r.raise_for_status()\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 400 and e.response.json().get(\"detail\") == \"Inactive user\":\n        prompt_reactivation()","preventionTips":["Surface disabled state to admins so they stop issuing tokens for suspended accounts.","Revoke outstanding tokens on disable.","Prefer 403 Forbidden for this case to avoid conflating it with malformed requests."],"tags":["fastapi","authentication","authorization","python","legacy-di"],"backgroundTag":null,"analyzedSha":"3e8d1526d83a90aaf7d6eb6dc682bf150f180b25","analyzedAt":"2026-08-11T02:34:52.986Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}