{"record":{"id":"d632bad9a2dcbeae","repo":"AdguardTeam/AdGuardHome","slug":"login-attempt-blocked-for-s","errorCode":null,"errorMessage":"login attempt blocked for %s","messagePattern":"login attempt blocked for (.+?)","errorType":"http","errorClass":null,"httpStatus":429,"severity":"warning","filePath":"internal/home/authhttp.go","lineNumber":583,"sourceCode":"\tr *http.Request,\n) (user *aghuser.User, err error) {\n\tlogin, pass, ok := r.BasicAuth()\n\tif !ok {\n\t\treturn nil, nil\n\t}\n\n\tvar remoteIP string\n\t// The real IP address of the client [realIP] cannot be used here without\n\t// taking trusted proxies into account due to security issues:\n\t//\n\t// See https://github.com/AdguardTeam/AdGuardHome/issues/2799.\n\tif remoteIP, err = netutil.SplitHost(r.RemoteAddr); err != nil {\n\t\treturn nil, fmt.Errorf(\"getting remote address: %w\", err)\n\t}\n\n\trateLimiter := mw.rateLimiter\n\tif left := rateLimiter.check(remoteIP); left > 0 {\n\t\treturn nil, fmt.Errorf(\"login attempt blocked for %s\", left)\n\t}\n\n\tdefer func() {\n\t\tif err != nil {\n\t\t\trateLimiter.inc(remoteIP)\n\n\t\t\treturn\n\t\t}\n\n\t\trateLimiter.remove(remoteIP)\n\t}()\n\n\tuser, _ = mw.users.ByLogin(ctx, aghuser.Login(login))\n\tif user == nil {\n\t\treturn nil, errInvalidLogin\n\t}\n\n\tok = user.Password.Authenticate(ctx, pass)","sourceCodeStart":565,"sourceCodeEnd":601,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/home/authhttp.go#L565-L601","documentation":"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.","triggerScenarios":"HTTP Basic Auth requests from an IP that exceeded failed-login limits; rateLimiter.check(remoteIP) returns a positive remaining duration.","commonSituations":"Monitoring scripts or API clients using Basic Auth with wrong credentials repeatedly; shared NAT IP accumulating failures; retry loops without backoff.","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"],"exampleFix":"// before\nresp = basic_auth(user, wrong_pass)\n# retry immediately on failure\n// after\nif resp.status_code == 401 and 'blocked for' in resp.text:\n    time.sleep(parse_duration(resp.text))","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Parse remaining block duration from error and sleep before retry\nif strings.Contains(err.Error(), \"blocked for\") {\n    d := parseDurationFromMsg(err.Error())\n    time.Sleep(d)\n}","preventionTips":["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"],"tags":["auth","basic-auth","rate-limit"],"backgroundTag":"auth-rate-limit-exceeded","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}