jackwener/OpenCLI · warning · EmptyResultError

No last encounter found for ${playerA.playerId} and ${player

Error message

No last encounter found for ${playerA.playerId} and ${playerB.playerId} in the latest ${recentMaps} maps from playerA

What it means

findLastEncounterSeries scans playerA's most recent maps for a mapstats page where both playerA and playerB appear, and throws this EmptyResultError when no such shared map is found within the requested window. The library treats 'these two players have not met in the analyzed range' as an empty result rather than a bug. It is raised from the public findLastEncounterSeries, called by lastEncounter.

Source

Thrown at clis/hltv/player-duel.js:267

  for (const candidate of candidates) {
    const mapUrl = candidate.details?.matchStatsUrl;
    if (!mapUrl || seen.has(candidate.matchStatsId)) continue;
    seen.add(candidate.matchStatsId);
    if (!playerBMatchIds.has(candidate.matchStatsId)) continue;

    const mapRows = await readMatchMap(page, mapUrl);
    if (!findPlayer(mapRows, playerB.playerId)) continue;

    const seriesUrl = await resolveStatsSeriesUrlFromMap(page, mapUrl);
    const mapUrls = await resolveMatchMapUrls(page, seriesUrl);
    return {
      mapUrls,
      matchedMapStatsId: candidate.matchStatsId,
      seriesUrl,
    };
  }

  throw new EmptyResultError(
    'hltv player-duel',
    `No last encounter found for ${playerA.playerId} and ${playerB.playerId} in the latest ${recentMaps} maps from playerA`,
  );
}

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));

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Increase the recentMaps argument to cover a longer window so the last encounter falls inside it
  2. Verify both playerIds/slugs resolve to active HLTV profiles with recent matches
  3. Check manually that the two players actually faced each other recently before calling
  4. Handle EmptyResultError at the call site and report 'no encounter' as a valid outcome

Example fix

// before
const series = await findLastEncounterSeries(page, { playerA, playerB, recentMaps: 20 });
// after
let series;
try {
  series = await findLastEncounterSeries(page, { playerA, playerB, recentMaps: 20 });
} catch (err) {
  if (err instanceof EmptyResultError) series = null;
  else throw err;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure window is wide enough before calling
if (!Number.isInteger(recentMaps) || recentMaps < 50) recentMaps = 100;

Type guard

function hasRecentMaps(playerA) { return Number.isFinite(playerA?.playerId); }

Try / catch

try {
  const series = await findLastEncounterSeries(page, { playerA, playerB, recentMaps });
} catch (err) {
  if (err instanceof EmptyResultError) return null; // no encounter is a valid answer
  throw err;
}

Prevention

When it happens

Trigger: Calling findLastEncounterSeries/lastEncounter with two player refs whose recent match histories share no mapstats pages, or with recentMaps set too small to cover their last head-to-head; one player has too few parsed rows or rows with missing matchStatsId.

Common situations: Comparing players from different regions/tiers who never met; shrinking recentMaps below the distance to their last real encounter; a player's recent maps mostly forfeits/removed matches not present in mapstats; stale player IDs after HLTV profile changes.

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


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/e348295705ae973f. Report an issue: GitHub.