Billionmail/BillionMail · warning

Invalid username or password

Error message

Invalid username or password

What it means

Login delegates credential checking to service.Account().Login. Any failure from that call — unknown username, wrong password, disabled account, underlying DB error — is collapsed into this generic message to avoid leaking which part failed.

Solutions

  1. Verify the username exists and the password is correct (try password reset)
  2. Check the accounts table was seeded/migrated in the target environment
  3. Inspect server logs to distinguish auth failure from infrastructure errors
  4. Confirm DB connectivity and that service.Account().Login is healthy

Example fix

// before
await api.login({ username: 'admin ', password: pw }) // stray space
// after
await api.login({ username: username.trim(), password: pw })
Defensive patterns

Strategy: try-catch

Validate before calling

if (!username?.trim() || !password) throw new Error('username and password required');

Try / catch

try {
  await api.login({ username: username.trim(), password });
} catch (err) {
  if (String(err.message).includes('Invalid username or password')) {
    // do not retry blindly; offer password reset / check server logs for infra errors
  }
}

Prevention

When it happens

Trigger: Submitting credentials for a non-existent account; wrong password; account locked/disabled; the account service erroring (DB down, migration missing) which is indistinguishable from bad credentials from the client's view.

Common situations: User mistypes username or password; caps-lock/keyboard layout issues; stale credentials after a password change; freshly deployed environment with an empty accounts table; DB connectivity problems making all logins fail.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/765766d51a8ebe10. Report an issue: GitHub.

Appendix: source

Thrown at core/internal/controller/rbac/rbac_v1_auth.go:84

		validateSuccess = false

		if req.ValidateCodeId == "" || req.ValidateCode == "" {
			err = fmt.Errorf("Validation code ID and code cannot be empty")
			return
		}

		if !service.VerifyCaptcha(req.ValidateCodeId, req.ValidateCode) {
			err = fmt.Errorf("Invalid validation code")
			return
		}

		validateSuccess = true
	}

	// Verify username and password
	account, err := service.Account().Login(ctx, req.Username, req.Password)
	if err != nil {
		err = fmt.Errorf("Invalid username or password")
		return
	}

	// Get account roles
	roles, err := service.Account().GetAccountRoles(ctx, account.AccountId)
	if err != nil {
		err = fmt.Errorf("Failed to get account roles")
		return
	}

	// Convert roles to role names
	roleNames := make([]string, 0, len(roles))
	for _, role := range roles {
		roleNames = append(roleNames, role.RoleName)
	}

	// Generate JWT token
	token, _, err := service.JWT().GenerateToken(account.AccountId, account.Username, roleNames)

View on GitHub (pinned to fc36c76c05)