koala73/worldmonitor · error · ValidationError

iso2 must be a 2-letter uppercase ISO country code

Error message

iso2 must be a 2-letter uppercase ISO country code

What it means

getCountryVulnerabilities normalizes req.iso2 (trim + uppercase) and requires /^[A-Z]{2}$/ before looking up the country in the vulnerability cohort payload. Invalid values throw this ValidationError on field 'iso2'.

Source

Thrown at server/worldmonitor/supply-chain/v1/get-country-vulnerabilities.ts:30

  VULNERABILITY_COHORT_KEY,
  countryVulnerabilityShardKey,
  enforceCommodityRedistributionPolicy,
  hasCurrentRedistributionPolicy,
  isMatchingShard,
  locateEntityShard,
  mapCommodityVulnerability,
  type RawVulnerabilityCohort,
  type RawCountryShard,
  stringValue,
} from './_vulnerability-projection';

export async function getCountryVulnerabilities(
  ctx: ServerContext,
  req: GetCountryVulnerabilitiesRequest,
): Promise<GetCountryVulnerabilitiesResponse> {
  const iso2 = (req.iso2 || '').trim().toUpperCase();
  if (!/^[A-Z]{2}$/.test(iso2)) {
    throw new ValidationError([{ field: 'iso2', description: 'iso2 must be a 2-letter uppercase ISO country code' }]);
  }

  const persistedPayload = await getCachedJson(VULNERABILITY_COHORT_KEY, true)
    .catch(() => null) as RawVulnerabilityCohort | null;
  const payload = hasCurrentRedistributionPolicy(persistedPayload) ? persistedPayload : null;
  let country = payload?.countries?.[iso2];
  let shardUnavailable = false;
  if (payload && !payload.countries) {
    const located = locateEntityShard(payload, payload.countryIds, iso2, countryVulnerabilityShardKey);
    if (located.status === 'unavailable') {
      shardUnavailable = true;
    } else if (located.status === 'read') {
      const shard = await getCachedJson(located.key, true)
        .catch(() => null) as RawCountryShard | null;
      if (isMatchingShard(payload, shard) && shard?.country?.iso2 === iso2) country = shard.country;
      else shardUnavailable = true;
    }
  }

View on GitHub (pinned to 9361220cc0)

Solutions

  1. Send an uppercase 2-letter ISO 3166-1 alpha-2 code ('BR', not 'BRA')
  2. Trim and uppercase client-side (server does this anyway)
  3. Validate with /^[A-Z]{2}$/ before the call
  4. Convert alpha-3/name inputs to alpha-2 via a lookup map before invoking

Example fix

// before
await getCountryVulnerabilities({ iso2: 'BRA' })
// after
const iso2 = String(raw).trim().toUpperCase();
if (!/^[A-Z]{2}$/.test(iso2)) throw new Error('iso2 must be alpha-2');
await getCountryVulnerabilities({ iso2: iso2 })
Defensive patterns

Strategy: validation

Validate before calling

function normalizeIso2(v) {
  const code = String(v || '').trim().toUpperCase();
  return /^[A-Z]{2}$/.test(code) ? code : null;
}

Type guard

function isIso2(v) {
  return typeof v === 'string' && /^[A-Z]{2}$/.test(v);
}

Try / catch

try {
  return await getCountryVulnerabilities({ iso2 });
} catch (e) {
  if (e.name === 'ValidationError' && e.field === 'iso2') {
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing empty/missing iso2, ISO-3 codes ('BRA'), full country names, numeric country codes, or lowercase codes (lowercase is accepted because of toUpperCase, but wrong length is not).

Common situations: Clients using UN M49 numeric codes or FIPS codes; form fields allowing free text; mixing alpha-2 and alpha-3 datasets.

Related errors


AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01). Data as JSON: /api/errors/51c0b75a4521efa8. Report an issue: GitHub.