bytedance/deer-flow · error · HTTPException
invalid_credentials
invalid_credentials
Error message
Incorrect email or password
What it means
401 from POST /api/auth/login: the local provider's authenticate() returned None — no user with that email exists or the password hash does not verify. The response body is a structured AuthErrorResponse with code 'invalid_credentials', and the failure is recorded against the client IP for the rate limiter.
Source
Thrown at backend/app/gateway/routers/auth.py:303
# ── Endpoints ─────────────────────────────────────────────────────────────
@router.post("/login/local", response_model=LoginResponse)
async def login_local(
request: Request,
response: Response,
form_data: OAuth2PasswordRequestForm = Depends(),
remember_me: bool = Form(default=True),
):
"""Local email/password login."""
client_ip = _get_client_ip(request)
_check_rate_limit(client_ip)
user = await get_local_provider().authenticate({"email": form_data.username, "password": form_data.password})
if user is None:
_record_login_failure(client_ip)
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=AuthErrorResponse(code=AuthErrorCode.INVALID_CREDENTIALS, message="Incorrect email or password").model_dump(),
)
_record_login_success(client_ip)
token = create_access_token(str(user.id), token_version=user.token_version)
_set_session_cookie(response, token, request, remember_me=remember_me)
return LoginResponse(
expires_in=get_auth_config().token_expiry_days * 24 * 3600,
needs_setup=user.needs_setup,
)
def _local_registration_enabled() -> bool:
"""Whether visitors may self-register a local account.
Local registration bypasses the OIDC provisioning policy entirelyView on GitHub (pinned to 1dd6ba1acb)
Solutions
- Verify the email is registered locally (or use the password-reset flow) and retype the password
- If the account is OAuth-only, log in via the SSO provider instead of local credentials
- Administrators can reset the user's password in the user store to restore local login
- Distinguish from lockout: 401 means credentials wrong; 429 means locked out
Defensive patterns
Strategy: try-catch
Try / catch
try { await login(email, password); } catch (e) {
if (e.status === 401 && e.body?.code === 'invalid_credentials') { showCredentialError(); return; }
throw e;
} Prevention
- Surface 'invalid credentials' distinctly from 429 lockout and 422 validation errors
- Offer password reset on repeated 401s instead of blind retries
When it happens
Trigger: POST /api/auth/login (OAuth2 form: username=email, password) with an unregistered email, a wrong password, or a user record whose password_hash does not match. Also when the user was created via OAuth and has no local password.
Common situations: Password reset not yet applied; user registered through SSO but attempts email/password login; stale token_version or migrated user store with un-migrated hashes; typos in email.
Related errors
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/7fd611a176bcf403.
Report an issue: GitHub.