koala73/worldmonitor · error · ConvexError

COUNTRIES_LIMIT_EXCEEDED

COUNTRIES_LIMIT_EXCEEDED

Error message

countries list capped at ${COUNTRIES_MAX} entries

What it means

Thrown by normalizeCountries when the cleaned/deduped country list exceeds COUNTRIES_MAX (50). Input is trimmed, uppercased, filtered to ^[A-Z]{2}$ shape, and deduped before the cap is checked, so only valid unique ISO-3166 alpha-2 codes count toward the limit. The cap is a defensive ceiling against patched-client abuse, not an ISO registry check.

Source

Thrown at convex/alertRules.ts:129

 * NOT a strict ISO-3166 registry check — invalid alpha-2 codes (e.g. "XX")
 * pass shape validation but the relay's includes() check just won't match
 * any real event country. We deliberately don't soft-couple this file to a
 * canonical registry list (that lives elsewhere as part of the
 * followed-countries primitive) — keep alertRules independently shippable.
 */
function normalizeCountries(input: string[]): string[] {
  const cleaned: string[] = [];
  const seen = new Set<string>();
  for (const raw of input) {
    if (typeof raw !== "string") continue;
    const upper = raw.trim().toUpperCase();
    if (!/^[A-Z]{2}$/.test(upper)) continue;
    if (seen.has(upper)) continue;
    seen.add(upper);
    cleaned.push(upper);
  }
  if (cleaned.length > COUNTRIES_MAX) {
    throw new ConvexError({
      code: "COUNTRIES_LIMIT_EXCEEDED",
      message: `countries list capped at ${COUNTRIES_MAX} entries`,
    });
  }
  return cleaned;
}

// Same defensive ceiling as COUNTRIES_MAX — mirrors the client-side market
// watchlist cap (src/services/market-watchlist.ts stops at 50 entries).
const TICKERS_MAX = 50;

/**
 * Shape-validate + normalize an inbound `tickers` array (#4922 U3).
 * Modeled EXACTLY on normalizeCountries above:
 *  - trim each entry
 *  - uppercase
 *  - keep only `^[A-Z][A-Z0-9&-]{0,11}(\.[A-Z]{1,3})?$` shapes — plain
 *    symbols (AAPL), share-class/conglomerate forms (BRK-B, M&M.NS) and

View on GitHub (pinned to ffec79ac33)

Solutions

  1. Reduce the countries array to at most 50 unique ISO-3166 alpha-2 codes before submitting.
  2. Drop invalid/duplicate entries client-side before the call (they waste nothing but make the count hard to reason about).
  3. If a legitimate need exceeds 50, reconsider the scope — the comment notes ~250 countries exist and 50 is already generous.

Example fix

// before
const countries = allWorldCountries; // 200+ entries
await setAlertRules(ctx, { ..., countries });
// after
const countries = prioritizeCountries(allWorldCountries).slice(0, 50);
await setAlertRules(ctx, { ..., countries });
Defensive patterns

Strategy: validation

Validate before calling

const COUNTRIES_MAX = 50;
function normalizeAndCapCountries(input) {
  const seen = new Set();
  const out = [];
  for (const raw of input) {
    const upper = String(raw).trim().toUpperCase();
    if (!/^[A-Z]{2}$/.test(upper) || seen.has(upper)) continue;
    seen.add(upper);
    out.push(upper);
    if (out.length === COUNTRIES_MAX) break;
  }
  return out;
}

Type guard

function isCountryList(input): input is string[] {
  return Array.isArray(input) && input.every(c => typeof c === 'string' && /^[A-Z]{2}$/.test(c.trim().toUpperCase()));
}

Try / catch

try {
  await setAlertRules(args);
} catch (e) {
  if (e instanceof ConvexError && /countries list capped/.test(String(e.message))) {
    // truncate and retry, or surface to user
  } else throw e;
}

Prevention

When it happens

Trigger: Calling setAlertRules, setAlertRulesForUser, setDigestSettingsForUser, setQuietHoursForUser, or setNotificationConfigForUser with a countries array containing more than 50 unique valid alpha-2 codes after normalization.

Common situations: A client patched to bypass UI limits submitting a bulk import; a migration script carrying an oversized country list; a watchlist sync that concatenates multiple region lists.

Related errors


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