jackwener/OpenCLI · warning · EmptyResultError
The selected players were not both present in the resolved m
Error message
The selected players were not both present in the resolved mapstats pages
What it means
buildDuelRows navigates the resolved mapstats pages and extracts a row for each selected player per map. It throws this EmptyResultError when zero map rows were produced, i.e. the two players were never both present in any of the resolved mapstats pages. This guards the summary row from being computed over an empty set.
Source
Thrown at clis/hltv/player-duel.js:289
}
async function buildDuelRows(page, args, mapUrls, scope, limit, context = {}) {
const playerA = parsePlayerRef(args.playerA);
const playerB = parsePlayerRef(args.playerB);
const rows = [];
for (const mapUrl of mapUrls.slice(0, limit)) {
const mapRows = await readMatchMap(page, mapUrl);
const playerARow = findPlayer(mapRows, playerA.playerId);
const playerBRow = findPlayer(mapRows, playerB.playerId);
if (!playerARow || !playerBRow) continue;
const matrix = playerARow.team === playerBRow.team ? [] : await readPerformanceKillMatrix(page, mapUrl);
const direct = parseDirectDuel(matrix, playerARow.playerName, playerBRow.playerName);
rows.push(toMapRow(scope, mapUrl, playerARow, playerBRow, direct));
}
if (rows.length === 0) {
throw new EmptyResultError('hltv player-duel', 'The selected players were not both present in the resolved mapstats pages');
}
return [toSummaryRow(scope, rows, context), ...rows];
}
cli({
site: 'hltv',
name: 'player-duel',
description: 'Compare two HLTV players on shared maps, including direct kill matrix when available',
access: 'read',
example: 'opencli hltv player-duel 19230/m0nesy 3741/niko --match https://www.hltv.org/stats/matches/mapstatsid/231594/falcons-vs-natus-vincere -f json',
domain: 'www.hltv.org',
strategy: Strategy.UI,
browser: true,
navigateBefore: false,
args: [
{ name: 'playerA', type: 'string', positional: true, required: true, help: 'First player ref: 19230/m0nesy, player URL, or stats player URL' },
{ name: 'playerB', type: 'string', positional: true, required: true, help: 'Second player ref: 3741/niko, player URL, or stats player URL' },
{ name: 'match', type: 'string', default: '', help: 'Optional HLTV match, stats series, or mapstats URL' },View on GitHub (pinned to 49907e53dc)
Solutions
- Confirm both players actually played in every resolved map (check for stand-ins)
- Re-resolve mapUrls so they point to mapstats pages containing both players
- Verify playerName strings match their HLTV display names exactly
- Catch EmptyResultError and surface 'players not in this match' to the user
Example fix
// before const mapUrls = [staleMapstatsUrl]; const rows = await buildDuelRows(page, args, mapUrls, scope, limit); // after const mapUrls = await resolveMapStatsUrls(page, matchUrl); // fresh, includes both players const rows = await buildDuelRows(page, args, mapUrls, scope, limit);
Defensive patterns
Strategy: validation
Validate before calling
// check both players appear on the resolved mapstats pages before building rows
const present = await page.evaluate((names) => names.every((n) => document.body.innerText.includes(n)), [playerA.playerName, playerB.playerName]);
if (!present) throw new Error('players not both present in mapstats'); Type guard
function bothPlayersExpected(mapUrls) { return Array.isArray(mapUrls) && mapUrls.length > 0; } Try / catch
try {
const rows = await buildDuelRows(page, args, mapUrls, scope, limit);
} catch (err) {
if (err instanceof EmptyResultError) return []; // no shared maps in this fixture
throw err;
} Prevention
- Re-resolve mapstats URLs right before building rows instead of caching them
- Account for stand-ins/substitutes between maps of a series
- Match players by id where possible, not fragile display-name text
- Check lineup changes on HLTV before comparing players in old matches
When it happens
Trigger: The mapUrls passed in (e.g. from a resolved match/series) contain mapstats pages where one or both player names do not appear; player name parsing fails to match table rows for every map; an empty or wrong mapUrls array is supplied.
Common situations: Passing a match URL for a game where a substitute played; lineup changed between series maps (stand-ins); stale mapstats URLs after HLTV restructures; mismatched playerName casing/special characters preventing row matching.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- BBC ${raw} feed returned no items.
- No last encounter found for ${playerA.playerId} and ${player
- No shared map rows found for ${playerA.playerId} and ${playe
- No player match rows matched team ${teamRef.teamId}/${teamRe
- No map-pool rows found for team ${teamId}/${slug}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/611eade8946ca107.
Report an issue: GitHub.