koala73/worldmonitor · error · RpcValidationError

provide exactly one of country_code, preset, or members.

Error message

provide exactly one of country_code, preset, or members.

What it means

The get-five-factor-scorecard tool requires exactly one of three mutually exclusive selectors: country_code, preset, or members. The handler counts how many are present (non-empty) and throws RpcValidationError when the count is not exactly 1 — i.e. zero selectors or more than one selector was supplied.

Source

Thrown at api/mcp/registry/rpc-tools.ts:2153

        },
      },
      required: [],
      oneOf: [
        { required: ['country_code'] },
        { required: ['preset'] },
        { required: ['members'] },
      ],
    },
    outputSchema: FIVE_FACTOR_SCORECARD_OUTPUT_SCHEMA,
    annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
    _coverageKeys: ['scorecard:five-factor:v1', 'seed-meta:scorecard:five-factor'],
    _execute: async (params, base, context) => {
      const countryCode = argStr(params.country_code).trim().toUpperCase();
      const preset = argStr(params.preset).trim().toUpperCase();
      const members = Array.isArray(params.members) ? params.members : [];
      const selectors = Number(countryCode.length > 0) + Number(preset.length > 0) + Number(members.length > 0);
      if (selectors !== 1) {
        throw new RpcValidationError('get-five-factor-scorecard', [{
          field: 'selection',
          description: 'provide exactly one of country_code, preset, or members.',
        }]);
      }

      const q = new URLSearchParams();
      let path: string;
      if (countryCode) {
        if (!/^[A-Z]{2}$/.test(countryCode)) {
          throw new RpcValidationError('get-five-factor-scorecard', [{
            field: 'country_code',
            description: 'must be an ISO 3166-1 alpha-2 country code.',
          }]);
        }
        path = '/api/scorecard/v1/get-five-factor-scorecard';
        q.set('countryCode', countryCode);
      } else {
        path = '/api/scorecard/v1/get-bloc-scorecard';

View on GitHub (pinned to 9361220cc0)

Solutions

  1. Send exactly one selector: either country_code, or preset, or members — delete the others from the request.
  2. For a single country use country_code: 'DE'; for a predefined basket use preset; for an ad-hoc group use members only.
  3. If building params programmatically, construct the params object conditionally so only one key is ever set.
  4. Empty strings count as absent — ensure the chosen selector is actually non-empty (argStr(...).trim() and members.length > 0).

Example fix

// before
callTool('get-five-factor-scorecard', { country_code: 'DE', preset: 'G10' })
// after
callTool('get-five-factor-scorecard', { country_code: 'DE' })
Defensive patterns

Strategy: validation

Validate before calling

const selectors = ['country_code', 'preset', 'members'].filter((k) => {
  const v = params[k];
  return Array.isArray(v) ? v.length > 0 : typeof v === 'string' && v.trim().length > 0;
});
if (selectors.length !== 1) throw new Error(`exactly one of country_code, preset, members required; got [${selectors}]`);

Type guard

function hasExactlyOneSelector(p: { country_code?: string; preset?: string; members?: unknown[] }): boolean {
  const n = Number(!!p.country_code?.trim()) + Number(!!p.preset?.trim()) + Number((p.members?.length ?? 0) > 0);
  return n === 1;
}

Try / catch

try {
  return await callTool('get-five-factor-scorecard', params);
} catch (err) {
  if (err instanceof RpcValidationError && err.fields?.[0]?.field === 'selection') {
    // rebuild params with a single selector and retry once
  } else throw err;
}

Prevention

When it happens

Trigger: Calling get-five-factor-scorecard with: none of the three fields set; two or three set at once (e.g. both country_code and preset); members provided as an array alongside country_code; or all fields present but empty strings/empty array (count 0).

Common situations: An agent template that fills multiple selector fields by default; a UI passing through stale params from a previous query type; confusion between the single-country and group (preset/members) variants of the scorecard API.

Related errors


AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01). Data as JSON: /api/errors/696639a28e053ede. Report an issue: GitHub.