koala73/worldmonitor · error · RpcValidationError
get-food-stocks validation: country_code is required and…
Error message
get-food-stocks validation: country_code is required and must be a 2-letter ISO 3166-1 alpha-2 code or WORLD
What it means
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.
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.
Example fix
// before
await callTool('get-food-stocks', { country_code: 'Germany' });
// after
await callTool('get-food-stocks', { country_code: 'DE' }); // or 'WORLD' Defensive patterns
Strategy: validation
Validate before calling
const code = typeof cc === 'string' ? cc.trim().toUpperCase() : '';
if (!/^(?:[A-Z]{2}|WORLD|WLD|_WORLD)$/.test(code)) throw new Error(`invalid country_code: ${cc}`); Type guard
const isCountryCode = (v) => typeof v === 'string' && /^(?:[A-Z]{2}|WORLD|WLD|_WORLD)$/.test(v.trim().toUpperCase()); Try / catch
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; } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- chokepointId must be a canonical chokepoint id
- Could not resolve to a country.
- Could not resolve to a country. Pass an ISO 3166-1 alpha-2…
- country must be an ISO 3166-1 alpha-2 country code, e.g…
- countryCode must be a 2-letter ISO 3166-1 alpha-2 code
AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-09-22).
Data as JSON: /api/errors/ce6b777ca0ede01b.
Report an issue: GitHub.
Appendix: source
Thrown at api/mcp/registry/rpc-tools.ts:1992
unit: { type: 'string', description: 'Always "1000 MT" (thousand metric tons).' },
source: {
type: 'string',
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.',
},
},
},
},
fetchedAt: { type: 'string' },
unavailable: { type: 'boolean' },
calorieWeightedStocksToUse: { type: 'number' },
},
},
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
_coverageKeys: ['resilience:food-stocks:v1', 'seed-meta:resilience:food-stocks'],
_execute: async (params, base, context, execution) => {
const countryCode = typeof params.country_code === 'string' ? params.country_code.trim().toUpperCase() : '';
if (!/^(?:[A-Z]{2}|WORLD|WLD|_WORLD)$/.test(countryCode)) {
throw new RpcValidationError('get-food-stocks', [{
field: 'country_code',
description: 'country_code is required and must be a 2-letter ISO 3166-1 alpha-2 code or WORLD',
}]);
}
const q = new URLSearchParams({ countryCode });
if (params.commodity) q.set('commodity', String(params.commodity).trim());
const qs = q.toString();
const url = `${base}/api/resilience/v1/get-food-stocks${qs ? `?${qs}` : ''}`;
const auth = await buildAuthHeaders(context, 'GET', url, null);
const res = await fetchMcpDownstream(url, {
headers: { ...auth, 'User-Agent': 'worldmonitor-mcp-edge/1.0' },
signal: AbortSignal.timeout(8_000),
}, execution);
await assertToolFetchOk(res, 'get-food-stocks');
return res.json();
},
_apiPaths: [
'GET /api/resilience/v1/get-food-stocks',View on GitHub (pinned to e586b8b4b8)