coder/code-server · warning · Error
Login rate limited!
Error message
Login rate limited!
What it means
The login POST handler (login.ts:78) calls limiter.canTry() and, if the caller has exceeded the allowed attempts within the window, throws the localized LOGIN_RATE_LIMIT message. This brute-force protection throttles repeated password guesses per IP.
Source
Thrown at src/node/routes/login.ts:78
const to = (typeof req.query.to === "string" && req.query.to) || "/"
if (await authenticated(req)) {
return redirect(req, res, to, { to: undefined })
}
next()
})
router.get("/", async (req, res) => {
res.send(await getRoot(req))
})
router.post<{}, string, { password?: string; base?: string } | undefined, { to?: string }>("/", async (req, res) => {
const password = sanitizeString(req.body?.password)
const hashedPasswordFromArgs = req.args["hashed-password"]
try {
// Check to see if they exceeded their login attempts
if (!limiter.canTry()) {
throw new Error(i18n.t("LOGIN_RATE_LIMIT") as string)
}
if (!password) {
throw new Error(i18n.t("MISS_PASSWORD") as string)
}
const passwordMethod = getPasswordMethod(hashedPasswordFromArgs)
const { isPasswordValid, hashedPassword } = await handlePasswordValidation({
passwordMethod,
hashedPasswordFromArgs,
passwordFromRequestBody: password,
passwordFromArgs: req.args.password,
})
if (isPasswordValid) {
// The hash does not add any actual security but we do it for
// obfuscation purposes (and as a side effect it handles escaping).
res.cookie(req.cookieSessionName, hashedPassword, getCookieOptions(req))View on GitHub (pinned to 51f90a376b)
Solutions
- Wait for the rate-limit window to elapse, then retry the login
- Verify the password is correct before retrying to avoid re-tripping the limiter
- For automated clients, space login attempts with backoff and cache the session cookie
Example fix
// before: tight retry loop
for (const pw of candidates) await tryLogin(pw) // trips limiter
// after: respect 429/rate-limit with backoff
async function loginWithBackoff(pw) {
for (let delay = 1000; ; delay *= 2) {
const r = await tryLogin(pw)
if (r.status === 429 || r.rateLimited) await sleep(delay)
else return r
}
} Defensive patterns
Strategy: retry
Validate before calling
// Client-side: track attempts and back off before the server trips the limiter
const MAX_ATTEMPTS = 5
const WINDOW_MS = 60_000
let attempts = 0, windowStart = Date.now()
function canTryLogin(): boolean {
if (Date.now() - windowStart > WINDOW_MS) { attempts = 0; windowStart = Date.now() }
return attempts++ < MAX_ATTEMPTS
}
if (!canTryLogin()) throw new Error("Login rate limited; wait before retrying") Try / catch
async function loginWithBackoff(password: string) {
for (let delay = 2000; delay <= 60_000; delay *= 2) {
try {
return await tryLogin(password)
} catch (e) {
if (e instanceof Error && /rate limited/i.test(e.message)) {
await new Promise((r) => setTimeout(r, delay))
continue
}
throw e
}
}
throw new Error("Exceeded login retries")
} Prevention
- Cache the session cookie and only re-login on 401
- Cap automated login retries and use exponential backoff
- Confirm the password is correct before retrying to avoid burning attempts
When it happens
Trigger: Repeated POST /login attempts (correct or incorrect) from the same client/IP beyond the limiter's threshold within its time window; automation that retries logins in a tight loop.
Common situations: Users mistyping the password many times; CI smoke tests hammering /login; a shared NAT IP getting throttled because of another user's failures.
Related errors
- Please pass in a password via the config file or environment
- Incorrect password
- --password can only be set in the config file or passed in v
- --hashed-password can only be set in the config file or pass
- --github-auth can only be set in the config file or passed i
AI-assisted analysis of coder/code-server@51f90a376b (2026-08-12).
Data as JSON: /api/errors/e607e281eef1341a.
Report an issue: GitHub.