{"record":{"id":"e2609412346b2244","repo":"koala73/worldmonitor","slug":"must-be-an-iso-3166-1-alpha-2-country-code","errorCode":null,"errorMessage":"must be an ISO 3166-1 alpha-2 country code.","messagePattern":"must be an ISO 3166-1 alpha-2 country code\\.","errorType":"validation","errorClass":"RpcValidationError","httpStatus":400,"severity":"error","filePath":"api/mcp/registry/rpc-tools.ts","lineNumber":2163,"sourceCode":"    annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },\n    _coverageKeys: ['scorecard:five-factor:v1', 'seed-meta:scorecard:five-factor'],\n    _execute: async (params, base, context) => {\n      const countryCode = argStr(params.country_code).trim().toUpperCase();\n      const preset = argStr(params.preset).trim().toUpperCase();\n      const members = Array.isArray(params.members) ? params.members : [];\n      const selectors = Number(countryCode.length > 0) + Number(preset.length > 0) + Number(members.length > 0);\n      if (selectors !== 1) {\n        throw new RpcValidationError('get-five-factor-scorecard', [{\n          field: 'selection',\n          description: 'provide exactly one of country_code, preset, or members.',\n        }]);\n      }\n\n      const q = new URLSearchParams();\n      let path: string;\n      if (countryCode) {\n        if (!/^[A-Z]{2}$/.test(countryCode)) {\n          throw new RpcValidationError('get-five-factor-scorecard', [{\n            field: 'country_code',\n            description: 'must be an ISO 3166-1 alpha-2 country code.',\n          }]);\n        }\n        path = '/api/scorecard/v1/get-five-factor-scorecard';\n        q.set('countryCode', countryCode);\n      } else {\n        path = '/api/scorecard/v1/get-bloc-scorecard';\n        if (preset) q.set('preset', preset);\n        else members.forEach((member) => q.append('members', String(member)));\n      }\n\n      const url = `${base}${path}?${q.toString()}`;\n      const auth = await buildAuthHeaders(context, 'GET', url, null);\n      const res = await fetch(url, {\n        headers: { ...auth, 'User-Agent': 'worldmonitor-mcp-edge/1.0' },\n        signal: AbortSignal.timeout(8_000),\n      });","sourceCodeStart":2145,"sourceCodeEnd":2181,"githubUrl":"https://github.com/koala73/worldmonitor/blob/9361220cc013571781071f0206e4d80fd14b2f7f/api/mcp/registry/rpc-tools.ts#L2145-L2181","documentation":"After selecting the country_code variant, get-five-factor-scorecard validates the value against /^[A-Z]{2}$/ (ISO 3166-1 alpha-2). Anything else — lowercase codes, 3-letter alpha-3 codes, full names — throws RpcValidationError on field country_code. The internal scorecard API expects the strict two-letter uppercase form.","triggerScenarios":"Calling get-five-factor-scorecard with country_code values like 'deu', 'DEU', 'Germany', 'D', or '' that survived the selector check but fail the alpha-2 regex.","commonSituations":"Agents emitting alpha-3 codes (ISO 3166-1 alpha-3) or FIPS codes; frontend inputs not normalized to uppercase; passing a human-readable country name because the selector check allowed it through as the single selector.","solutions":["Normalize the input to a two-letter uppercase ISO 3166-1 alpha-2 code before calling ('DEU' -> 'DE', 'germany' -> 'DE').","Reuse the registry's resolveCountryCode helper (as requireCountryCode does) to convert names/aliases to alpha-2 client-side.","Validate with /^[A-Z]{2}$/ in the caller before dispatching the RPC.","For scorecard queries on non-ISO entities, switch to the preset or members selector instead."],"exampleFix":"// before\ncallTool('get-five-factor-scorecard', { country_code: 'DEU' })\n// after\nconst cc = resolveCountryCode('DEU'); // 'DE'\ncallTool('get-five-factor-scorecard', { country_code: cc })","handlingStrategy":"validation","validationCode":"function isAlpha2Country(v: unknown): v is string {\n  return typeof v === 'string' && /^[A-Z]{2}$/.test(v);\n}\nif (!isAlpha2Country(params.country_code)) throw new Error('country_code must be ISO 3166-1 alpha-2, e.g. \"DE\"');","typeGuard":"function isIsoAlpha2(v: unknown): v is string {\n  return typeof v === 'string' && /^[A-Z]{2}$/.test(v);\n}","tryCatchPattern":"try {\n  return await callTool('get-five-factor-scorecard', { country_code: cc });\n} catch (err) {\n  if (err instanceof RpcValidationError && err.fields?.[0]?.field === 'country_code') {\n    const fixed = resolveCountryCode(cc);\n    if (fixed) return await callTool('get-five-factor-scorecard', { country_code: fixed });\n  }\n  throw err;\n}","preventionTips":["Normalize alpha-3 codes and names to alpha-2 via resolveCountryCode before calling.","Uppercase country inputs at the boundary (the regex requires A-Z).","Validate with /^[A-Z]{2}$/ in any client that constructs scorecard requests.","Prefer shared country-resolution helpers over ad-hoc string handling."],"tags":["validation","mcp","rpc","iso-3166","country-code"],"backgroundTag":"rpc-validation-error","analyzedSha":"9361220cc013571781071f0206e4d80fd14b2f7f","analyzedAt":"2026-09-01T10:32:37.851Z","contentChangedAt":"2026-09-01T10:32:37.851Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}