koala73/worldmonitor · error · ValidationError
emailCheck.reason
Error message
emailCheck.reason
What it means
The email passed the regex but validateEmail (server/_shared/email-validation.ts) rejected it on content, and the violation description carries the specific reason. Four possible reasons: offensive local/domain part, a disposable/temp-mail domain (mailinator, yopmail, guerrillamail, ...), a typo TLD (.con, .coma, .gmai), or a live MX lookup via Cloudflare DoH showing the domain cannot receive mail. The MX check fails OPEN on DNS errors/timeouts, so the mail-rejection reason only fires on a definitive empty MX answer.
Source
Thrown at server/worldmonitor/leads/v1/register-interest.ts:330
} else {
const turnstileOk = await verifyTurnstile({
token: req.turnstileToken || '',
ip,
logPrefix: '[register-interest]',
});
if (!turnstileOk) {
throw new ApiError(403, 'Bot verification failed', '');
}
}
const { email, source, appVersion, referredBy } = req;
if (!email || email.length > MAX_EMAIL_LENGTH || !EMAIL_RE.test(email)) {
throw new ValidationError([{ field: 'email', description: 'Invalid email address' }]);
}
const emailCheck = await validateEmail(email);
if (!emailCheck.valid) {
throw new ValidationError([{ field: 'email', description: emailCheck.reason }]);
}
const safeSource = source ? source.slice(0, MAX_META_LENGTH) : 'unknown';
const safeAppVersion = appVersion ? appVersion.slice(0, MAX_META_LENGTH) : 'unknown';
const safeReferredBy = referredBy ? referredBy.slice(0, 20) : undefined;
const convexUrl = process.env.CONVEX_URL;
if (!convexUrl) {
throw new ApiError(503, 'Registration service unavailable', '');
}
const client = new ConvexHttpClient(convexUrl);
const result = (await client.mutation(api.registerInterest.register, {
email,
source: safeSource,
appVersion: safeAppVersion,
referredBy: safeReferredBy,
})) as ConvexRegisterResult;View on GitHub (pinned to a96956387a)
Solutions
- Use a permanent mailbox on a domain with MX records
- If the reason mentions a typo TLD, correct the domain ending and resubmit
- If you own the domain, add MX records so it can receive the confirmation mail
- Do not retry with random disposable domains — each is checked
Example fix
// before
await registerInterest({ email: 'signup@mailinator.com', ... }); // "Disposable email addresses are not allowed..."
// after
await registerInterest({ email: 'signup@yourcompany.com', ... }); // real domain with MX Defensive patterns
Strategy: validation
Validate before calling
// Mirror the cheap checks client-side (disposable list + typo TLD); MX stays server-side
const domain = email.trim().toLowerCase().split('@')[1] ?? '';
if (DISPOSABLE_DOMAINS.has(domain)) return show('Disposable email addresses are not allowed.');
if (TYPO_TLDS.has(domain.split('.').pop() ?? '')) return show('This email domain looks like a typo.');
await registerInterest({ ...req, email }); Type guard
function isPlausiblyDeliverableEmail(v: unknown): v is string {
if (!isSyntacticEmail(v)) return false;
const domain = v.toLowerCase().split('@')[1] ?? '';
return !DISPOSABLE_DOMAINS.has(domain) && !TYPO_TLDS.has(domain.split('.').pop() ?? '');
} Try / catch
try { await registerInterest(req); }
catch (e) {
if (isValidationError(e) && e.violations?.some(v => v.field === 'email')) {
const reason = e.violations.find(v => v.field === 'email')!.description;
showFieldError('email', reason); // reason text is user-safe: disposable / typo TLD / no MX
return;
}
throw e;
} Prevention
- Block disposable-domain signup options in the UI before the captcha step
- Suggest corrections for .con/.gmai typo endings
- If a user's own domain is rejected for no MX, tell them to fix mail routing — retrying changes nothing
When it happens
Trigger: Registering with user@mailinator.com or any of ~40 disposable domains; "user@gmial.con" (typo TLD); a domain that exists but has no MX records (e.g. a parked domain or a bare A-record-only hostname); offensive words in the local part.
Common situations: Users masking with temp-mail services to farm referral codes (the endpoint exists precisely to stop this); typosquat endings like .con; someone using their vanity domain that has no mail routing configured.
Related errors
- Invalid email address
- Invalid email
- get_intel_timeline requires at least one of domain ("conflic
- INCOMPATIBLE_DELIVERY
- COUNTRIES_LIMIT_EXCEEDED
AI-assisted analysis of koala73/worldmonitor@a96956387a (2026-08-21).
Data as JSON: /api/errors/b781d2ac83becded.
Report an issue: GitHub.