koala73/worldmonitor · error · Error
Custom scorecard bloc members must belong to the public…
Error message
Custom scorecard bloc members must belong to the public rankable country universe.
What it means
Even well-formed, unique, uppercase ISO-2 codes are only accepted if each belongs to the public rankable country universe (checked via isInRankableUniverse(member)). The scorecard ranks countries against a curated dataset universe; microstates, territories, or codes without underlying indicator data are excluded so blocs stay comparable. Codes outside the universe (e.g., 'VA', 'HK' depending on the current universe, or 'AQ') throw this error.
Solutions
- Filter members through the published rankable-universe list (or isInRankableUniverse if you can import it) before sending.
- Use the API's country listing (listScorableCountries / static index) to populate the picker so only rankable codes are offered.
- After filtering, confirm ≥2 members remain and meet all other rules; otherwise switch to a preset.
- Pin your client to the API version whose universe your lists were built against.
Example fix
// before
resolveBlocSelection({ members: ['US', 'VA', 'MC'] }); // throws: VA/MC not rankable
// after
const members = raw.filter((m) => isInRankableUniverse(m));
if (members.length >= 2) resolveBlocSelection({ members }); Defensive patterns
Strategy: validation
Validate before calling
const rankable = await fetchRankableUniverse(); // from listScorableCountries or static index
const members = raw.filter((m) => rankable.includes(m));
if (members.length < 2) throw new Error('not enough rankable members for a bloc'); Type guard
function isRankable(code: string, universe: ReadonlySet<string>): code is string {
return universe.has(code);
} Try / catch
try {
const bloc = await getBlocScorecard({ members });
} catch (err) {
if (err.message.includes('rankable country universe')) {
const excluded = members.filter((m) => !universe.has(m));
return badRequest({ excluded, hint: 'choose from listScorableCountries' });
}
throw err;
} Prevention
- Populate pickers from listScorableCountries, not raw ISO-3166 lists
- Filter territories/microstates out of custom selections
- Re-filter on API version upgrades (universe can change)
- Keep a cached copy of the rankable universe client-side for pre-validation
When it happens
Trigger: Calling getBlocScorecardWithReader with a custom list containing any non-rankable code: territories (e.g., 'GL', 'PR'), microstates ('MC', 'SM'), or any ISO-2 code absent from the published rankable universe, even if the rest of the list is valid.
Common situations: 1) A world country-picker lists all ISO-3166 entries including dependencies and microstates that the dataset doesn't rank; 2) universe changes between versions — a code previously rankable is dropped after a data-source revision; 3) users deliberately test edge codes ('AQ' Antarctica).
Related errors
- Custom scorecard bloc members must be unique.
- Custom scorecard blocs require 2-30 members.
- Select exactly one scorecard bloc preset or custom member…
- Unknown scorecard bloc preset
- Custom scorecard bloc members must be uppercase ISO-2 codes.
AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01).
Data as JSON: /api/errors/6bf7b0fb64ac90f2.
Report an issue: GitHub.
Appendix: source
Thrown at server/worldmonitor/scorecard/v1/_bloc-presets.ts:42
};
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)