koala73/worldmonitor · error · ValidationError
countryCode must be a 2-letter ISO 3166-1 alpha-2 code
Error message
countryCode must be a 2-letter ISO 3166-1 alpha-2 code
What it means
A ValidationError thrown by createGetResilienceIndicators in server/worldmonitor/resilience/v1/get-resilience-indicators.ts when req.countryCode fails normalizedCountryCode() — i.e., it is not a string that trims/uppercases into a 2-letter ISO 3166-1 alpha-2 code. The RPC layer deliberately rejects bad input before touching caches or the seed reader, so clients get a structured field-level error instead of an internal failure.
Source
Thrown at server/worldmonitor/resilience/v1/get-resilience-indicators.ts:285
const now = dependencies.now ?? (() => new Date());
const readStaticMeta = dependencies.readStaticMeta
?? (() => strictResilienceSeedReader(RESILIENCE_STATIC_META_KEY));
const hasInjectedBuildDependency = dependencies.reader != null
|| dependencies.now != null
|| dependencies.readStaticMeta != null;
const responseCache = dependencies.responseCache === undefined
? hasInjectedBuildDependency
? null
: cacheResilienceIndicatorResponse
: dependencies.responseCache;
return async (
_ctx: ServerContext,
req: GetResilienceIndicatorsRequest,
): Promise<GetResilienceIndicatorsResponse> => {
const countryCode = normalizedCountryCode(req.countryCode);
if (!countryCode) {
throw new ValidationError([{
field: 'countryCode',
description: 'countryCode must be a 2-letter ISO 3166-1 alpha-2 code',
}]);
}
if (!hasInjectedBuildDependency && dependencies.responseCache === undefined) {
const generation = await ensureResilienceScoreGenerationCached(countryCode);
return toGetResilienceIndicatorsResponse(
countryCode,
null,
generation.trace.snapshot,
{
now: now(),
dataVersion: generation.trace.dataVersion,
formula: generation.trace.formula,
schemaVersion: generation.trace.schemaVersion,
constructVersions: generation.trace.constructVersions,
},View on GitHub (pinned to 9361220cc0)
Solutions
- Send a valid ISO 3166-1 alpha-2 code, uppercase, exactly 2 letters (e.g., 'DE', 'US').
- Normalize on the client: value.trim().toUpperCase() and validate with /^[A-Z]{2}$/ before sending.
- Map names/ISO-3/demonym inputs through a lookup table to ISO-2 before calling.
- Handle the ValidationError response (field: 'countryCode') in the client by prompting the user to reselect a country rather than retrying blindly.
Example fix
// before
const res = await getResilienceIndicators({ countryCode: country.name }); // 'Germany'
// after
const cc = country.iso2?.trim().toUpperCase() ?? '';
if (!/^[A-Z]{2}$/.test(cc)) throw new Error(`Cannot map ${country.name} to ISO-2`);
const res = await getResilienceIndicators({ countryCode: cc }); Defensive patterns
Strategy: validation
Validate before calling
const cc = String(req.countryCode ?? '').trim().toUpperCase();
if (!/^[A-Z]{2}$/.test(cc)) throw new ValidationError([{ field: 'countryCode', description: 'countryCode must be a 2-letter ISO 3166-1 alpha-2 code' }]); Type guard
function hasValidCountryCode(req: { countryCode?: string | null }): req is { countryCode: string } {
return typeof req.countryCode === 'string' && /^[A-Z]{2}$/.test(req.countryCode.trim().toUpperCase());
} Try / catch
try {
return await getResilienceIndicators(req);
} catch (err) {
if (err.name === 'ValidationError' && err.fields?.some((f) => f.field === 'countryCode')) {
return 400 response prompting reselection; // not retryable
}
throw err;
} Prevention
- Validate ISO-2 format client-side before every RPC call
- Use a country picker bound to ISO-2 codes, never free text
- Map locale tags / names to ISO-2 with a lookup table
- Snapshot-test request builders so countryCode is always populated
When it happens
Trigger: Any call to getResilienceIndicators whose request has countryCode set to '', undefined, null, a lowercase-with-garbage string, an ISO-3 code ('USA'), a full country name ('Germany'), or a code longer/shorter than 2 letters.
Common situations: 1) Client sends a country name or numeric UN M49 code from a search box without mapping to ISO-2; 2) frontend sends lowercase 'de' from a locale tag split incorrectly ('de-DE'.split('-')[0] works, but 'de_DE' fails); 3) tests omit the field entirely; 4) version drift where an older client sends a deprecated 'cc' field while the API reads 'countryCode'.
Related errors
- country must be an ISO 3166-1 alpha-2 country code, e.g. "UA
- Could not resolve ${JSON.stringify(echoCountryInput(raw))} t
- must be an ISO 3166-1 alpha-2 country code.
- get_intel_timeline requires at least one of domain ("conflic
- fromIso2 and toIso2 must be valid 2-letter ISO country codes
AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01).
Data as JSON: /api/errors/28a945d30d1ae7db.
Report an issue: GitHub.