Hmbown/CodeWhale · critical · Error
Missing login limiter
Error message
Missing login limiter
What it means
The admin login route gates every login attempt behind a Cloudflare rate-limit binding, env.ADMIN_LOGIN_LIMITER. If the binding is absent the code deliberately throws instead of allowing logins ungated — an unavailable limiter must not disable the gate.
Solutions
- Add the ADMIN_LOGIN_LIMITER rate-limiting binding to wrangler.toml/wrangler.jsonc and redeploy.
- Run the route through `wrangler dev` (or Miniflare) so bindings are available instead of plain `next dev`.
- Verify with `wrangler deployments list` / `wrangler versions view` that the deployed version carries the binding.
Example fix
// before (wrangler.jsonc)
{
"compatibility_date": "2025-01-01"
}
// after (wrangler.jsonc)
{
"compatibility_date": "2025-01-01",
"ratelimits": [{ "name": "ADMIN_LOGIN_LIMITER", "namespace_id": "1001" }]
} Defensive patterns
Strategy: fallback
Try / catch
try {
const res = await fetch("/api/admin/login", { method: "POST", body: creds });
} catch (err) {
if (String(err.message).includes("Missing login limiter")) {
// Deployment misconfiguration: verify Cloudflare bindings before retrying.
reportDeploymentConfigError(err);
}
} Prevention
- Declare ADMIN_LOGIN_LIMITER in wrangler config and keep it in every environment (prod, preview, local wrangler dev).
- Add a CI check that wrangler config includes the required bindings before deploy.
- Never bypass the limiter check locally — run auth routes through wrangler dev, not plain next dev.
When it happens
Trigger: POST /api/admin/login when the deployed Worker/Pages environment lacks the ADMIN_LOGIN_LIMITER binding (e.g. wrangler.toml missing the rate limiting binding, or a local dev run without `wrangler dev` bindings).
Common situations: Deploying web/ without updating wrangler config after the limiter was introduced; running `next dev` locally where Cloudflare bindings do not exist; preview environments created from an outdated config.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- refusing unauthenticated app-server bind on non-loopback…
- --set is not supported by auth commands; use a saved config
- 127
- a Gitee access token is not configured in the Codewhale…
- A pinned task provider requires an explicit model
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/26830007382aa3bc.
Report an issue: GitHub.
Appendix: source
Thrown at web/app/api/admin/login/route.ts:32
}
export async function POST(req: Request) {
const env = await getAgentEnv();
const url = new URL(req.url);
const localeFromQuery = pickLocale(url.searchParams.get("locale"));
if (!env.MAINTAINER_TOKEN) {
return new NextResponse("Not configured", {
status: 503,
headers: { "Cache-Control": "no-store" },
});
}
// One maintainer principal: key by that account, never by attacker-controlled
// headers or submitted tokens. The binding shares counters across isolates
// in a Cloudflare location. An unavailable limiter must not disable the gate.
try {
if (!env.ADMIN_LOGIN_LIMITER) throw new Error("Missing login limiter");
const { success } = await env.ADMIN_LOGIN_LIMITER.limit({ key: "codewhale-web:admin-login" });
if (!success) {
return new NextResponse("Too many login attempts", {
status: 429,
headers: { "Cache-Control": "no-store", "Retry-After": "60" },
});
}
} catch {
return new NextResponse("Login temporarily unavailable", {
status: 503,
headers: { "Cache-Control": "no-store", "Retry-After": "60" },
});
}
let form: URLSearchParams;
try {
form = await readBoundedUrlEncodedForm(req, MAX_LOGIN_BODY_BYTES);
} catch (error) {View on GitHub (pinned to 433685b202)