AdguardTeam/AdGuardHome · warning
login attempt blocked for %s
Error message
login attempt blocked for %s
What it means
Basic-auth attempt rejected because the source IP is currently blocked by the login rate limiter; the message includes how long the block remains. The deferred handler also counts this failed attempt.
Source
Thrown at internal/home/authhttp.go:583
r *http.Request,
) (user *aghuser.User, err error) {
login, pass, ok := r.BasicAuth()
if !ok {
return nil, nil
}
var remoteIP string
// The real IP address of the client [realIP] cannot be used here without
// taking trusted proxies into account due to security issues:
//
// See https://github.com/AdguardTeam/AdGuardHome/issues/2799.
if remoteIP, err = netutil.SplitHost(r.RemoteAddr); err != nil {
return nil, fmt.Errorf("getting remote address: %w", err)
}
rateLimiter := mw.rateLimiter
if left := rateLimiter.check(remoteIP); left > 0 {
return nil, fmt.Errorf("login attempt blocked for %s", left)
}
defer func() {
if err != nil {
rateLimiter.inc(remoteIP)
return
}
rateLimiter.remove(remoteIP)
}()
user, _ = mw.users.ByLogin(ctx, aghuser.Login(login))
if user == nil {
return nil, errInvalidLogin
}
ok = user.Password.Authenticate(ctx, pass)View on GitHub (pinned to b41aefbe51)
Solutions
- Correct the Basic Auth credentials being used
- Wait for the block window to expire before retrying
- Add exponential backoff / stop-on-401 in automated clients
- Use a distinct source IP or trusted-proxy config where applicable
Example fix
// before
resp = basic_auth(user, wrong_pass)
# retry immediately on failure
// after
if resp.status_code == 401 and 'blocked for' in resp.text:
time.sleep(parse_duration(resp.text)) Defensive patterns
Strategy: retry
Try / catch
// Parse remaining block duration from error and sleep before retry
if strings.Contains(err.Error(), "blocked for") {
d := parseDurationFromMsg(err.Error())
time.Sleep(d)
} Prevention
- Use correct credentials from the first attempt in scripts
- Back off on 401 responses; don't loop Basic Auth
- Prefer session cookies over per-request Basic Auth
When it happens
Trigger: HTTP Basic Auth requests from an IP that exceeded failed-login limits; rateLimiter.check(remoteIP) returns a positive remaining duration.
Common situations: Monitoring scripts or API clients using Basic Auth with wrong credentials repeatedly; shared NAT IP accumulating failures; retry loops without backoff.
Related errors
- auth: blocked for %s
- getting remote address: %w
- generating password hash: %w
- auth: parsing remote address: %w
- searching session by token: %w
AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27).
Data as JSON: /api/errors/d632bad9a2dcbeae.
Report an issue: GitHub.