koala73/worldmonitor · warning · RpcValidationError
get-intel-timeline: domain Required unless country is set. O
Error message
get-intel-timeline: domain Required unless country is set. One of conflict, military, or energy. / country Required unless domain is set. ISO 3166-1 alpha-2, uppercase (e.g. UA).
What it means
Thrown by the `get_intel_timeline` MCP tool's `_execute` in api/mcp/registry/rpc-tools.ts:2441 as an RpcValidationError mapped to JSON-RPC -32602. The underlying history route requires at least one scope — a `domain` or a `country` — because an unscoped read of all intel history is not allowed server-side (it would 400). The registry checks this locally to return actionable field-level violations and avoid the round-trip and the generic -32603 path (WORLDMONITOR-10Y).
Source
Thrown at api/mcp/registry/rpc-tools.ts:3136
required: ['records', 'partial', 'upstreamUnavailable'],
properties: {
records: { type: 'array', description: 'Scoped history, newest first.', items: INTEL_HISTORY_RECORD_SCHEMA },
partial: { type: 'boolean', description: 'True when the bounded post-filter window may omit older matching events.' },
upstreamUnavailable: { type: 'boolean', description: 'True when the history store could not be reached. `records` is then empty because the read failed — never read that as "nothing happened in this window".' },
},
},
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
_execute: async (params, base, context, execution) => {
// Scope is mandatory server-side (a 400 from the handler). Checking it
// here turns an opaque downstream failure into actionable -32602
// violations (RpcValidationError) and saves the round-trip; the handler
// stays the enforcing authority. A plain Error would land as -32603 +
// Sentry error (WORLDMONITOR-10Y).
const domain = typeof params.domain === 'string' ? params.domain.trim() : '';
const country = normalizeCountry(params.country);
assertIntelHistoryCountry('get-intel-timeline', country);
if (!domain && !country) {
throw new RpcValidationError('get-intel-timeline', [
{
field: 'domain',
description: 'Required unless country is set. One of conflict, military, or energy.',
},
{
field: 'country',
description: 'Required unless domain is set. ISO 3166-1 alpha-2, uppercase (e.g. UA).',
},
]);
}
const query = new URLSearchParams();
addStringParam(query, 'domain', domain);
addStringParam(query, 'country', country);
addIntelHistoryNumber(query, 'from', params.from);
addIntelHistoryNumber(query, 'to', params.to);
addIntelHistoryNumber(query, 'limit', Math.min(Number(params.limit ?? MCP_HISTORY_TIMELINE_MAX_LIMIT), MCP_HISTORY_TIMELINE_MAX_LIMIT));
View on GitHub (pinned to 9361220cc0)
Solutions
- Pass `domain` as one of "conflict", "military", or "energy"
- Or pass `country` as an uppercase ISO 3166-1 alpha-2 code (e.g. "UA"); supplying both narrows to their intersection
- If you intended a broad query, note it is intentionally unsupported — pick a domain or country scope per call
Example fix
// before
tools.get_intel_timeline({ from: 1700000000000 })
// after
tools.get_intel_timeline({ domain: 'conflict', from: 1700000000000 }) Defensive patterns
Strategy: validation
Validate before calling
const DOMAINS = new Set(['conflict', 'military', 'energy']);
const params: Record<string, unknown> = {};
if (input.domain && DOMAINS.has(input.domain)) params.domain = input.domain;
else if (isIsoAlpha2(input.country)) params.country = input.country;
else {
// refuse to call without a scope instead of firing an unscoped request
throw new Error('get_intel_timeline requires domain or country');
}
await tools.get_intel_timeline(params); Type guard
function hasTimelineScope(p: { domain?: unknown; country?: unknown }): boolean {
const d = typeof p.domain === 'string' ? p.domain.trim() : '';
const c = typeof p.country === 'string' ? p.country.trim().toUpperCase() : '';
return (d === 'conflict' || d === 'military' || d === 'energy') || /^[A-Z]{2}$/.test(c);
} Try / catch
try {
await tools.get_intel_timeline(params);
} catch (e) {
if (e?.code === -32602) {
// read e.data.violations, add domain or country, then retry once with a valid scope
} else throw e;
} Prevention
- Always pick a scope (domain or country) when composing get_intel_timeline calls
- Trim and validate user-supplied domain/country strings before passing them through
When it happens
Trigger: Calling `get_intel_timeline` with neither `domain` nor `country`, or with values that normalize to empty strings (e.g. `domain: " "`, or a `country` that `normalizeCountry` reduces to empty such as an unknown name).
Common situations: Agents exploring the tool without arguments; callers passing whitespace-only strings; callers passing a country name that normalization strips, leaving both scopes empty; passing an invalid domain value that trims to something empty.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- get_intel_timeline requires at least one of domain ("conflic
- ${label} HTTP 400
- country must be an ISO 3166-1 alpha-2 country code, e.g. "UA
- Could not resolve ${JSON.stringify(echoCountryInput(raw))} t
- provide exactly one of country_code, preset, or members.
AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-08-27).
Data as JSON: /api/errors/666119f68f15d04f.
Report an issue: GitHub.