koala73/worldmonitor · warning · ApiError

Too many recent submissions for this email; try again later.

Error message

Too many recent submissions for this email; try again later.

What it means

The Convex backend answered 429, meaning this email has submitted contact requests too recently. The handler surfaces it as an explicit 429 ApiError with a retry-later message — this is a deliberate rate-limit signal, not an outage.

Solutions

  1. Wait for the rate-limit window to elapse and retry with the same email
  2. Back off client-side: disable submit after first click and honor the 429 with a countdown UI
  3. Use a different email address if the request is legitimately for another contact
  4. Raise or tune the rate-limit window in the Convex submitContact action if it is too strict for legitimate traffic

Example fix

// before
if (response.status === 429) {
  throw new ApiError(429, 'Too many recent submissions for this email; try again later.', '');
}
// after
if (response.status === 429) {
  const retryAfter = response.headers.get('retry-after');
  throw new ApiError(429, 'Too many recent submissions for this email; try again later.', '', retryAfter ? { 'retry-after': retryAfter } : undefined);
}
Defensive patterns

Strategy: retry

Validate before calling

const lastSubmitAt = Number(localStorage.getItem('contact:lastSubmitAt') ?? 0);
if (Date.now() - lastSubmitAt < RATE_WINDOW_MS) show('Please wait before submitting again.');

Type guard

null

Try / catch

try {
  await submitContact(form);
} catch (e) {
  if (e instanceof ApiError && e.status === 429) {
    showCountdownAndRetryLater(e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: Posting /submit-contact repeatedly with the same email within the backend's rate-limit window, causing the Convex action to respond with HTTP 429.

Common situations: A user double-clicking the submit button, automated scripts or retries hammering the endpoint, a shared corporate mail gateway reusing one address, or integration tests reusing a fixture email.

Related errors


AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15). Data as JSON: /api/errors/c95da7df795acbad. Report an issue: GitHub.

Appendix: source

Thrown at server/worldmonitor/leads/v1/submit-contact.ts:180

        'Content-Type': 'application/json',
        'User-Agent': 'worldmonitor-leads/1.0',
        'x-convex-shared-secret': secret,
      },
      body: JSON.stringify({
        name: safeName,
        email: email.trim(),
        organization: safeOrg,
        phone: safePhone,
        message: safeMsg,
        source: safeSource,
      }),
      signal: AbortSignal.timeout(10_000),
    });
  } catch {
    throw new ApiError(503, 'Service unavailable', '');
  }
  if (response.status === 429) {
    throw new ApiError(429, 'Too many recent submissions for this email; try again later.', '');
  }
  if (response.status === 422) {
    throw new ApiError(422, 'Please use a corporate email address.', '');
  }
  if (!response.ok) {
    throw new ApiError(503, 'Service unavailable', '');
  }
  const result: unknown = await response.json().catch(() => null);
  if (!result || typeof result !== 'object' || !('status' in result) || result.status !== 'sent') {
    throw new ApiError(503, 'Service unavailable', '');
  }

  const emailSent = await sendNotificationEmail(
    safeName,
    email.trim(),
    safeOrg,
    safePhone,
    safeMsg,

View on GitHub (pinned to 7d06c8633d)