koala73/worldmonitor · error
get-china-decision-signals returned an invalid canonical…
Error message
get-china-decision-signals returned an invalid canonical payload
What it means
Plain Error thrown in the get-china-decision-signals tool (api/mcp/registry/rpc-tools.ts:707): the wire payloadJson string was present and JSON.parse succeeded, but the parsed value failed the isChinaDecisionSignalSnapshot type guard. The MCP side validates the canonical snapshot shape before returning it; a parse-OK-but-invalid payload means the producer wrote a snapshot that no longer matches the guard — schema drift or a malformed write.
Solutions
- Fetch the endpoint directly, extract payloadJson, JSON.parse it, and diff the top-level shape against isChinaDecisionSignalSnapshot's requirements
- Update the guard or the producer so both agree on the snapshot schema, and ship them together
- Check the writer of intelligence:china-decision-signals:v1 for partial/truncated writes if the shape looks right
- Redeploy the stale side (registry vs intelligence handler) once aligned
Defensive patterns
Strategy: try-catch
Type guard
function isInvalidCanonicalPayload(e) {
return e instanceof Error
&& e.message === 'get-china-decision-signals returned an invalid canonical payload';
} Try / catch
try {
const snapshot = await fetchChinaDecisionSignals(context, execution);
} catch (e) {
if (isInvalidCanonicalPayload(e)) {
// Schema drift between snapshot producer and MCP guard — inspect and realign, do not retry
await reportSchemaDrift('intelligence:china-decision-signals:v1');
throw e;
}
throw e;
} Prevention
- Version the snapshot schema and gate deploys on the type guard passing in CI against a fixture
- Update isChinaDecisionSignalSnapshot and the producer in the same change set
- Log the parsed payload's top-level keys on guard failure to accelerate drift diagnosis
When it happens
Trigger: The producer that writes intelligence:china-decision-signals:v1 changed its snapshot schema (added/renamed/retyped required fields) while the MCP guard still expects the old shape, or a bug wrote a partial/malformed snapshot that serializes fine but fails structure validation.
Common situations: Producer deployed ahead of MCP registry without updating the guard (or the reverse). New optional-to-required field promotion in the snapshot. A truncated write under producer timeout. Version skew in worktrees/preview deployments.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- get-china-decision-signals returned no canonical payload
- Could not resolve to a country.
- country must be an ISO 3166-1 alpha-2 country code, e.g…
- get-country-intel-brief HTTP
- get-intel-timeline: domain Required unless country is set…
AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-08-21).
Data as JSON: /api/errors/7dc5e0faea5dd6b5.
Report an issue: GitHub.
Appendix: source
Thrown at api/mcp/registry/rpc-tools.ts:1130
const url = `${base}/api/intelligence/v1/get-china-decision-signals`;
const auth = await buildAuthHeaders(context, 'GET', url, null);
const response = await fetchMcpDownstream(url, {
headers: { ...auth, 'User-Agent': 'worldmonitor-mcp-edge/1.0' },
signal: AbortSignal.timeout(12_000),
}, execution);
await assertMcpToolFetchOk(response, {
operation: 'get-china-decision-signals',
tool: 'get_china_decision_signals',
auth: context,
execution,
});
const wire = await response.json() as { payloadJson?: unknown };
if (typeof wire.payloadJson !== 'string') {
throw new Error('get-china-decision-signals returned no canonical payload');
}
const payload = JSON.parse(wire.payloadJson) as unknown;
if (!isChinaDecisionSignalSnapshot(payload)) {
throw new Error('get-china-decision-signals returned an invalid canonical payload');
}
return payload;
},
_coverageKeys: [
'china:policy-events:v1',
'military:cross-strait-activity:v1',
'military:cross-strait-activity-bootstrap:v1',
'market:china:corporate-disclosures:v1',
'intelligence:china-decision-signals:v1',
],
_apiPaths: [
'GET /api/intelligence/v1/get-china-decision-signals',
],
},
{
name: 'get_procurement_opportunities',
_outputBudgetBytes: 65536,
description: 'Search open global public-procurement opportunities through the canonical Pro route. Default output is 10 compact records (maximum 25), without descriptions or submission/eligibility payloads. automationFit is keyword relevance evidence only, never bidding eligibility; participationMode "unknown" remains unknown.',View on GitHub (pinned to e586b8b4b8)