QuantumNous/new-api · error · Error

Login failed

Error message

Login failed

What it means

Thrown in the sign-in form when a successful, non-2FA login response fails the isAuthBundle structural check — res.data lacks the required auth bundle fields (access token, session, user). It protects handleLoginSuccess from persisting a malformed bundle that would immediately break authenticated requests.

Source

Thrown at web/src/features/auth/sign-in/components/user-auth-form.tsx:187

    try {
      const res = await login({
        username: data.username,
        password: data.password,
        turnstile: submittedTurnstileToken,
      })

      if (res.success) {
        if (res.data && 'require_2fa' in res.data && res.data.require_2fa) {
          if (!res.data.flow_token) {
            throw new Error(t('Login flow expired. Please sign in again.'))
          }
          setPending2FAFlowToken(res.data.flow_token)
          redirectTo2FA()
          return
        }

        if (!isAuthBundle(res.data)) {
          throw new Error(t('Login failed'))
        }
        await handleLoginSuccess(res.data, redirectTo)
        toast.success(t('Welcome back!'))
      }
    } catch (error: unknown) {
      if (axios.isAxiosError(error)) return
      toast.error(error instanceof Error ? error.message : loginFailedMessage)
    } finally {
      setIsLoading(false)
    }
  }

  const handleOpenWeChatDialog = () => {
    if (requiresLegalConsent && !agreedToLegal) {
      toast.error(legalConsentErrorMessage)
      return
    }

View on GitHub (pinned to e2c7aa7b10)

Solutions

  1. Log res.data shape and compare with isAuthBundle's required fields; the check is the source of truth for the expected contract.
  2. Align backend login response with the AuthBundle shape (access_token, token_type, access_expires_at, session, user) or update isAuthBundle after a deliberate contract change.
  3. Check axios response interceptors are not unwrapping/replacing data.
  4. Ensure frontend/backend deploy together.
Defensive patterns

Strategy: type-guard

Type guard

// isAuthBundle is the guard; keep it authoritative for the login contract
if (res.success && !isAuthBundle(res.data)) { /* contract violation path */ }

Try / catch

try {
  if (res.success && !isAuthBundle(res.data)) throw new Error(t('Login failed'))
} catch (error) {
  if (axios.isAxiosError(error)) return // transport errors handled elsewhere
  toast.error(error instanceof Error ? error.message : loginFailedMessage)
}

Prevention

When it happens

Trigger: POST login returns success:true but data is null, partial (missing session/user/token), or an unexpected shape (e.g. only {require_2fa:false}).

Common situations: Backend contract drift after an upgrade (renamed or restructured login payload); response transformed by an interceptor; backend returning success:true on a degraded path without a full bundle.

Related errors


AI-assisted analysis of QuantumNous/new-api@e2c7aa7b10 (2026-08-15). Data as JSON: /api/errors/01666667896013d7. Report an issue: GitHub.