{"record":{"id":"74f5f46e5c4eb1ab","repo":"invoke-ai/InvokeAI","slug":"incorrect-email-or-password","errorCode":null,"errorMessage":"Incorrect email or password","messagePattern":"Incorrect email or password","errorType":"http","errorClass":"HTTPException","httpStatus":401,"severity":"error","filePath":"invokeai/app/api/routers/auth.py","lineNumber":224,"sourceCode":"\n    Raises:\n        HTTPException: 401 if credentials are invalid or user is inactive\n        HTTPException: 403 if multiuser mode is disabled\n    \"\"\"\n    config = ApiDependencies.invoker.services.configuration\n\n    # Check if multiuser is enabled\n    if not config.multiuser:\n        raise HTTPException(\n            status_code=status.HTTP_403_FORBIDDEN,\n            detail=\"Multiuser mode is disabled. Authentication is not required in single-user mode.\",\n        )\n\n    user_service = ApiDependencies.invoker.services.users\n    user = user_service.authenticate(login_request.email, login_request.password)\n\n    if user is None:\n        raise HTTPException(\n            status_code=status.HTTP_401_UNAUTHORIZED,\n            detail=\"Incorrect email or password\",\n            headers={\"WWW-Authenticate\": \"Bearer\"},\n        )\n\n    if not user.is_active:\n        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=\"User account is disabled\")\n\n    # Create token with appropriate expiration\n    expires_delta = timedelta(\n        days=TOKEN_EXPIRATION_REMEMBER_ME if login_request.remember_me else TOKEN_EXPIRATION_NORMAL\n    )\n    token_data = TokenData(\n        user_id=user.user_id,\n        email=user.email,\n        is_admin=user.is_admin,\n        remember_me=login_request.remember_me,\n        token_epoch=user.token_epoch,","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/api/routers/auth.py#L206-L242","documentation":"login authenticates via user_service.authenticate(email, password); when no active user matches, it raises 401 with 'Incorrect email or password' and a WWW-Authenticate: Bearer header. The same error covers both wrong email and wrong password (no user enumeration).","triggerScenarios":"POST /auth/login with an email that has no user record, or a password that fails the hash check for that user, while multiuser mode is enabled.","commonSituations":"Typo'd email; password changed or reset on another client; stale credentials stored in a frontend after the DB was recreated; users table wiped by re-initializing the database.","solutions":["Verify the email matches an existing user (check the users list via an admin account)","Re-enter the password carefully; use the admin 'reset password' flow if forgotten","Re-run /auth/setup to create the admin if the database was recreated","Clear cached credentials in the client and retry"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"# before calling the API, sanity-check inputs client-side\nif not email or '@' not in email or not password:\n    raise ValueError('Email and password are required')","typeGuard":"def credentials_valid(creds: dict) -> bool:\n    return bool(creds.get('email')) and bool(creds.get('password'))","tryCatchPattern":"try:\n    resp = requests.post(f'{base}/auth/login', json={'email': email, 'password': password})\n    resp.raise_for_status()\nexcept requests.HTTPError as e:\n    if e.response.status_code == 401:\n        prompt_reenter_credentials()  # never retry blindly — show login form","preventionTips":["Prompt the user to re-enter credentials on 401 instead of retrying in a loop","Never cache passwords; re-prompt after DB resets or password changes","Use the admin password-reset flow instead of guessing","Check for keyboard layout/whitespace issues in stored credentials"],"tags":["http-401","authentication","invalid-credentials"],"backgroundTag":"invalid-login-credentials","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}