coder/code-server · warning · Error

Incorrect password

Error message

Incorrect password

What it means

Thrown by the POST /login handler after a password is supplied but fails validation in handlePasswordValidation(). Before throwing, the handler calls limiter.removeToken() to consume a rate-limit token and logs a structured 'Failed login attempt' record. Like the missing-password error it is caught locally and rendered back into login.html as an inline error, so the caller receives a 200 with HTML, not a 401.

Source

Thrown at src/node/routes/login.ts:116

      const to = (typeof req.query.to === "string" && req.query.to) || "/"
      return redirect(req, res, to, { to: undefined })
    }

    // Note: successful logins should not count against the RateLimiter
    // which is why this logic must come after the successful login logic
    limiter.removeToken()

    console.error(
      "Failed login attempt",
      JSON.stringify({
        xForwardedFor: req.headers["x-forwarded-for"],
        remoteAddress: req.connection.remoteAddress,
        userAgent: req.headers["user-agent"],
        timestamp: Math.floor(new Date().getTime() / 1000),
      }),
    )

    throw new Error(i18n.t("INCORRECT_PASSWORD") as string)
  } catch (error: any) {
    const renderedHtml = await getRoot(req, error)
    res.send(renderedHtml)
  }
})

View on GitHub (pinned to 51f90a376b)

Solutions

  1. Confirm the correct password for the currently configured auth: check PASSWORD / --hashed-password on the running code-server process.
  2. If using --hashed-password, regenerate the hash and confirm its method (argon2i/d, sha256) matches what handlePasswordValidation expects.
  3. Wait for the rate limiter window to reset if repeated wrong attempts triggered LOGIN_RATE_LIMIT (the limiter blocks further tries).
  4. Check server logs for the 'Failed login attempt' JSON entries to see source IP/UA of failing attempts.

Example fix

// regenerate an argon2 hashed password
echo -n 'mypassword' | argon2 somesalt -id -l 32 -p 2 -t 3 -e
# then start with: code-server --hashed-password '$argon2id$...'
Defensive patterns

Strategy: validation

Validate before calling

// Before login, sanity-check the password against the expected method locally where possible.
// For argon2 hashed passwords you can verify with the argon2 module:
import argon2 from 'argon2'
const ok = await argon2.verify(storedHash, candidate)
if (!ok) throw new Error('Password does not match the configured hash')

Type guard

// Ensure the configured hashed password is a known method before relying on it.
function isKnownHashMethod(h: string): boolean {
  return h.startsWith('$argon2') || /^[a-f0-9]{64}$/i.test(h) // argon2 or sha256
}

Try / catch

// The route's try/catch already catches INCORRECT_PASSWORD and renders it inline.
// In a programmatic client, handle the re-rendered HTML / cookie absence:
try {
  await postLogin(password)
  if (!document.cookie.includes(cookieName)) throw new Error('login failed')
} catch (e) { /* show error, do NOT retry in a tight loop (rate limiter!) */ }

Prevention

When it happens

Trigger: POST /login with a non-empty password that does not match the configured password method: a wrong plaintext/argon2/sha256 hash comparison, an expired PASSWORD env var, or a hashed-password arg whose hash the supplied password does not satisfy. Each wrong attempt also drains the RateLimiter (2/min, 12/hour).

Common situations: User mistypes the password; the server was restarted with a different PASSWORD or --hashed-password value; the client cached an old password; copy-paste of a hash with a missing or extra character; switching password methods (plain -> argon2) without updating clients.

Related errors


AI-assisted analysis of coder/code-server@51f90a376b (2026-08-12). Data as JSON: /api/errors/a0a06deabd43227d. Report an issue: GitHub.