{"record":{"id":"ce6b777ca0ede01b","repo":"koala73/worldmonitor","slug":"get-food-stocks-validation-country-code-is-required-and-must","errorCode":null,"errorMessage":"get-food-stocks validation: country_code is required and must be a 2-letter ISO 3166-1 alpha-2 code or WORLD","messagePattern":"get-food-stocks validation: country_code is required and must be a 2-letter ISO 3166-1 alpha-2 code or WORLD","errorType":"validation","errorClass":"RpcValidationError","httpStatus":null,"severity":"error","filePath":"api/mcp/registry/rpc-tools.ts","lineNumber":1992,"sourceCode":"              unit: { type: 'string', description: 'Always \"1000 MT\" (thousand metric tons).' },\n              source: {\n                type: 'string',\n                description: '\"psd\" = USDA. \"faostat\" = FAOSTAT Food Balances production and domestic-supply gap fill. FAOSTAT stock fields are placeholder 0 values when presence flags are false.',\n              },\n            },\n          },\n        },\n        fetchedAt: { type: 'string' },\n        unavailable: { type: 'boolean' },\n        calorieWeightedStocksToUse: { type: 'number' },\n      },\n    },\n    annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },\n    _coverageKeys: ['resilience:food-stocks:v1', 'seed-meta:resilience:food-stocks'],\n    _execute: async (params, base, context, execution) => {\n      const countryCode = typeof params.country_code === 'string' ? params.country_code.trim().toUpperCase() : '';\n      if (!/^(?:[A-Z]{2}|WORLD|WLD|_WORLD)$/.test(countryCode)) {\n        throw new RpcValidationError('get-food-stocks', [{\n          field: 'country_code',\n          description: 'country_code is required and must be a 2-letter ISO 3166-1 alpha-2 code or WORLD',\n        }]);\n      }\n      const q = new URLSearchParams({ countryCode });\n      if (params.commodity) q.set('commodity', String(params.commodity).trim());\n      const qs = q.toString();\n      const url = `${base}/api/resilience/v1/get-food-stocks${qs ? `?${qs}` : ''}`;\n      const auth = await buildAuthHeaders(context, 'GET', url, null);\n      const res = await fetchMcpDownstream(url, {\n        headers: { ...auth, 'User-Agent': 'worldmonitor-mcp-edge/1.0' },\n        signal: AbortSignal.timeout(8_000),\n      }, execution);\n      await assertToolFetchOk(res, 'get-food-stocks');\n      return res.json();\n    },\n    _apiPaths: [\n      'GET /api/resilience/v1/get-food-stocks',","sourceCodeStart":1974,"sourceCodeEnd":2010,"githubUrl":"https://github.com/koala73/worldmonitor/blob/e586b8b4b80f595aa7ece295eec10d76f2921240/api/mcp/registry/rpc-tools.ts#L1974-L2010","documentation":"The get-food-stocks MCP tool validates its required `country_code` parameter against `/^(?:[A-Z]{2}|WORLD|WLD|_WORLD)$/` after trimming and uppercasing. If the value is missing, not a string, or not a 2-letter ISO 3166-1 alpha-2 code or a WORLD sentinel, it throws an RpcValidationError describing the expected format. This fail-fast guard keeps malformed country codes from reaching the downstream food-stocks API query.","triggerScenarios":"Calling the get-food-stocks tool with country_code omitted, with a full country name like \"Germany\", with a 3-letter code like \"DEU\", with lowercase-with-spaces strings that trim to something non-matching (e.g. \"D E\"), or with a non-string value such as a number.","commonSituations":"LLM clients passing country names instead of ISO codes; clients using ISO 3166-1 alpha-3 codes; callers forgetting the parameter entirely; case sensitivity confusion resolved only if the caller pre-uppercases.","solutions":["Pass a valid 2-letter ISO 3166-1 alpha-2 code (e.g. \"DE\", \"US\") or \"WORLD\" for the country_code parameter.","Trim and uppercase the value before calling: \"de\" works because the tool normalizes, but \" de \" with internal whitespace does not.","If using a 3-letter alpha-3 code, convert it to alpha-2 first (e.g. \"DEU\" -> \"DE\").","If using a country name, resolve it to its alpha-2 code with an ISO lookup table before calling."],"exampleFix":"// before\nawait callTool('get-food-stocks', { country_code: 'Germany' });\n// after\nawait callTool('get-food-stocks', { country_code: 'DE' }); // or 'WORLD'","handlingStrategy":"validation","validationCode":"const code = typeof cc === 'string' ? cc.trim().toUpperCase() : '';\nif (!/^(?:[A-Z]{2}|WORLD|WLD|_WORLD)$/.test(code)) throw new Error(`invalid country_code: ${cc}`);","typeGuard":"const isCountryCode = (v) => typeof v === 'string' && /^(?:[A-Z]{2}|WORLD|WLD|_WORLD)$/.test(v.trim().toUpperCase());","tryCatchPattern":"try { await callTool('get-food-stocks', { country_code }) } catch (e) { if (String(e.message).includes('country_code is required')) { /* fall back to WORLD or fix the code */ } else throw e; }","preventionTips":["Keep an ISO 3166-1 alpha-2 lookup table and always resolve country names/codes through it","Normalize (trim + uppercase) codes at the call site","Reject alpha-3 codes early in client-side input validation","Default to 'WORLD' when no specific country is intended"],"tags":["validation","mcp","input-validation","iso-codes"],"backgroundTag":"invalid-argument-value","analyzedSha":"e586b8b4b80f595aa7ece295eec10d76f2921240","analyzedAt":"2026-09-22T01:50:49.965Z","contentChangedAt":"2026-09-22T01:50:49.965Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}