koala73/worldmonitor · error · Error
Custom scorecard blocs require 2-30 members.
Error message
Custom scorecard blocs require 2-30 members.
What it means
When a custom member list (no preset) is supplied, resolveBlocSelection requires between 2 and 30 country codes inclusive. Lists of length 0 hit the XOR error first; lists of exactly 1 or longer than 30 hit this error. The bounds keep scorecard comparisons statistically meaningful and the request payload/cache key bounded.
Source
Thrown at server/worldmonitor/scorecard/v1/_bloc-presets.ts:36
ASEAN: { id: 'ASEAN', label: 'ASEAN', members: ['BN', 'KH', 'ID', 'LA', 'MY', 'MM', 'PH', 'SG', 'TH', 'TL', 'VN'] },
NATO: {
id: 'NATO',
label: 'NATO',
members: ['AL', 'BE', 'BG', 'CA', 'HR', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GR', 'HU', 'IS', 'IT', 'LV', 'LT', 'LU', 'ME', 'NL', 'MK', 'NO', 'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE', 'TR', 'GB', 'US'],
},
};
export function resolveBlocSelection(input: { preset?: string; members?: string[] }): ScorecardBlocSelection {
const preset = String(input.preset || '').trim();
const members = Array.isArray(input.members) ? input.members : [];
if (Boolean(preset) === (members.length > 0)) {
throw new Error('Select exactly one scorecard bloc preset or custom member list.');
}
if (preset) {
if (!(preset in SCORECARD_BLOC_PRESETS)) throw new Error(`Unknown scorecard bloc preset: ${preset}`);
return SCORECARD_BLOC_PRESETS[preset as ScorecardBlocPreset];
}
if (members.length < 2 || members.length > 30) throw new Error('Custom scorecard blocs require 2-30 members.');
if (members.some((member) => !/^[A-Z]{2}$/.test(member))) {
throw new Error('Custom scorecard bloc members must be uppercase ISO-2 codes.');
}
if (new Set(members).size !== members.length) throw new Error('Custom scorecard bloc members must be unique.');
if (members.some((member) => !isInRankableUniverse(member))) {
throw new Error('Custom scorecard bloc members must belong to the public rankable country universe.');
}
const sorted = [...members].sort();
return { id: `custom:${sorted.join('-')}`, label: sorted.join(' + '), members: sorted };
}
View on GitHub (pinned to 9361220cc0)
Solutions
- Provide 2–30 members; if you only need one country, call the single-country resilience score endpoint instead.
- For larger comparisons, split into multiple bloc requests of ≤30 and merge client-side.
- Cap the country picker UI at 30 selections before allowing submit.
- Deduplicate first — duplicates count toward array length but fail later on the uniqueness check.
Example fix
// before
resolveBlocSelection({ members: ['US'] }); // throws: only 1 member
// after
if (members.length < 2) return getResilienceScore({ countryCode: members[0] });
resolveBlocSelection({ members: members.slice(0, 30) }); Defensive patterns
Strategy: validation
Validate before calling
const members = (sel.members ?? []).filter(Boolean);
if (members.length < 2 || members.length > 30) throw new Error('Custom scorecard blocs require 2-30 members.'); Try / catch
try {
const bloc = await getBlocScorecard({ members });
} catch (err) {
if (err.message.includes('require 2-30 members')) {
if (members.length === 1) return getResilienceScore({ countryCode: members[0] });
return badRequest('select between 2 and 30 countries');
}
throw err;
} Prevention
- Cap the multi-select UI at 30 and require at least 2
- Route single-country comparisons to the score endpoint, not blocs
- Split oversized comparisons into multiple ≤30-member calls
- Deduplicate before counting length
When it happens
Trigger: Calling getBlocScorecardWithReader with { members: ['US'] } (only 1 member) or with more than 30 members (e.g., dumping all ~200 ISO codes into a custom bloc). Zero members instead raises 'Select exactly one scorecard bloc preset or custom member list.'
Common situations: 1) A UI lets users pick a single country for comparison — must use the single-country scorecard API instead of a bloc; 2) 'select all' in a country picker sends the full universe; 3) scripted requests that join multiple blocs into one 40-member list instead of separate calls.
Related errors
- Select exactly one scorecard bloc preset or custom member li
- Unknown scorecard bloc preset: ${preset}
- Custom scorecard bloc members must be unique.
- Custom scorecard bloc members must belong to the public rank
- INVALID_COMPANY_PATCH
AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01).
Data as JSON: /api/errors/a606a7664933e910.
Report an issue: GitHub.