koala73/worldmonitor · error · ConvexError
rate_limited
rate_limited
Error message
Too many recent submissions for this email; try again later.
What it means
Per-email rate limit in the contactMessages submit handler: the normalized email already has PER_EMAIL_LIMIT submissions within PER_EMAIL_WINDOW_MS (queried via the by_normalized_email_received index). The throttle caps spam and abuse from a single address.
Solutions
- Wait for the throttle window to elapse before submitting again
- If genuine users hit it, tune PER_EMAIL_LIMIT and PER_EMAIL_WINDOW_MS to the real traffic pattern
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at convex/contactMessages.ts:91 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-08-21).
Data as JSON: /api/errors/5cbca9f34fc0e181.
Report an issue: GitHub.
Appendix: source
Thrown at convex/contactMessages.ts:88
kind: "FREE_EMAIL_NOT_ALLOWED",
message: "Please use a corporate email address.",
});
}
const normalizedEmail = email.toLowerCase();
// Throttle: cap recent submissions per email. Index lookup keeps this O(matches),
// which the limit caps at PER_EMAIL_LIMIT + 1.
const windowStart = Date.now() - PER_EMAIL_WINDOW_MS;
const recent = await ctx.db
.query("contactMessages")
.withIndex("by_normalized_email_received", (q) =>
q.eq("normalizedEmail", normalizedEmail).gte("receivedAt", windowStart),
)
.take(PER_EMAIL_LIMIT + 1);
if (recent.length >= PER_EMAIL_LIMIT) {
throw new ConvexError({
kind: "rate_limited",
message: "Too many recent submissions for this email; try again later.",
});
}
await ctx.db.insert("contactMessages", {
name,
email,
organization,
phone,
message,
source,
receivedAt: Date.now(),
normalizedEmail,
});
return { status: "sent" as const };
},
});View on GitHub (pinned to 7d06c8633d)