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

  1. Use a permanent mailbox on a domain with MX records
  2. If the reason mentions a typo TLD, correct the domain ending and resubmit
  3. If you own the domain, add MX records so it can receive the confirmation mail
  4. 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

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


AI-assisted analysis of koala73/worldmonitor@a96956387a (2026-08-21). Data as JSON: /api/errors/b781d2ac83becded. Report an issue: GitHub.