Billionmail/BillionMail · warning
Login failed too many times, please try again after %d secon
Error message
Login failed too many times, please try again after %d seconds
What it means
Login implements rate limiting: after too many failed attempts a cache key stores a release timestamp. When a login is attempted while blocked, the handler returns this error with the remaining seconds until the block expires. The seconds value is releaseTime minus now.
Source
Thrown at core/internal/controller/rbac/rbac_v1_auth.go:60
// Login success
if loginSuccessFlag {
public.RemoveCache(cacheKey)
return
}
// Increment login retries
public.SetCache(cacheKey, loginRetries+1, 300)
}()
if loginRetries >= maxRetries {
k := "USER_LOGIN_RETRIES_RELEASE_TIME:" + clientIp
releaseTime, blocked := public.GetCache(k).(int64)
if !blocked {
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 = trueView on GitHub (pinned to fc36c76c05)
Solutions
- Wait the reported number of seconds before retrying
- Reset the password via the recovery flow instead of guessing
- Clear/invalidate the rate-limit cache key (Redis) if the block is confirmed to be from a shared IP or attacker
- Increase blockTime/threshold configuration if too aggressive for legitimate users
Example fix
// before (immediate retry) await login(user, wrongPassword) // after (respect the block) const waitSec = 60; // from error message await new Promise(r => setTimeout(r, waitSec * 1000)); await login(user, password)
Defensive patterns
Strategy: try-catch
Validate before calling
// track local failure count and back off before hitting the limit if (++localFailures >= 4) await sleep(backoffMs);
Try / catch
try {
await api.login(creds);
} catch (err) {
const m = String(err.message).match(/try again after (\d+) seconds/);
if (m) await sleep(parseInt(m[1], 10) * 1000 + 500); // retry after block expires
else throw err;
} Prevention
- Verify credentials before resubmitting (password manager)
- Stop guessing and use password reset after 2-3 failures
- Avoid shared automation scripts with hardcoded credentials
- Use exponential backoff on login failures
When it happens
Trigger: Repeated failed login attempts (wrong password) exceeding the configured threshold; a user retrying rapidly while already blocked; automated scripts/bots hammering the login endpoint; a stale cache entry from earlier failures still counting against the user.
Common situations: User forgets password and keeps guessing; CI/monitoring scripts using outdated credentials; shared IPs (office NAT) where multiple users' failures accumulate on one key; password manager with stale credentials auto-submitting.
Related errors
- Invalid username or password
- Validation code ID and code cannot be empty
- Invalid validation code
- Failed to get account roles
- failed to get validate code: %w
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/78c812a2adafb90c.
Report an issue: GitHub.