Billionmail/BillionMail · warning

Invalid validation code

Error message

Invalid validation code

What it means

After confirming the captcha fields are present, Login verifies them via service.VerifyCaptcha. If the verification service rejects the ID/code pair, this error is returned and login is aborted (validateSuccess stays false).

Source

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

			releaseTime = time.Now().Unix() + int64(blockTime)
			public.SetCache(k, releaseTime, blockTime)
		}

		err = fmt.Errorf("Login failed too many times, please try again after %d seconds", releaseTime-time.Now().Unix())
		return
	}

	// Check if validation code is required
	if mustValidateCode {
		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

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Re-request a fresh captcha and retry with the new code
  2. Ensure the captcha store (Redis/session) is shared across all app instances
  3. Submit each captcha exactly once — regenerate after any failed attempt
  4. Check captcha TTL and make the UI refresh the image before expiry

Example fix

// before
// retrying login with the same old captcha
await api.login({ ...body, validate_code: sameCode })
// after
const fresh = await api.getCaptcha();
await api.login({ ...body, validate_code_id: fresh.id, validate_code: newUserInput })
Defensive patterns

Strategy: retry

Validate before calling

// captcha is single-use and time-limited; refresh it if older than ~2 min
if (captchaFetchedAt && Date.now() - captchaFetchedAt > 120_000) captcha = await api.getCaptcha();

Try / catch

try {
  await api.login(body);
} catch (err) {
  if (String(err.message).includes('Invalid validation code')) {
    const fresh = await api.getCaptcha();
    // re-prompt user and retry once with the new code
  } else throw err;
}

Prevention

When it happens

Trigger: User types the captcha wrong; the captcha has expired (one-time token already used or TTL elapsed); ValidateCodeId reused across attempts; captcha backend (session/redis) lost state so the stored answer is gone; distributed deployment where verification hits a different Redis than generation.

Common situations: Expired captcha left on screen while the user took too long; double-submit sending the same captcha twice; multiple app replicas without a shared captcha store; typos in case-sensitive codes.

Related errors


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