{"record":{"id":"e348295705ae973f","repo":"jackwener/OpenCLI","slug":"no-last-encounter-found-for-playera-playerid-an","errorCode":null,"errorMessage":"No last encounter found for ${playerA.playerId} and ${playerB.playerId} in the latest ${recentMaps} maps from playerA","messagePattern":"No last encounter found for (.+?) and (.+?) in the latest (.+?) maps from playerA","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"warning","filePath":"clis/hltv/player-duel.js","lineNumber":267,"sourceCode":"  for (const candidate of candidates) {\n    const mapUrl = candidate.details?.matchStatsUrl;\n    if (!mapUrl || seen.has(candidate.matchStatsId)) continue;\n    seen.add(candidate.matchStatsId);\n    if (!playerBMatchIds.has(candidate.matchStatsId)) continue;\n\n    const mapRows = await readMatchMap(page, mapUrl);\n    if (!findPlayer(mapRows, playerB.playerId)) continue;\n\n    const seriesUrl = await resolveStatsSeriesUrlFromMap(page, mapUrl);\n    const mapUrls = await resolveMatchMapUrls(page, seriesUrl);\n    return {\n      mapUrls,\n      matchedMapStatsId: candidate.matchStatsId,\n      seriesUrl,\n    };\n  }\n\n  throw new EmptyResultError(\n    'hltv player-duel',\n    `No last encounter found for ${playerA.playerId} and ${playerB.playerId} in the latest ${recentMaps} maps from playerA`,\n  );\n}\n\nasync function buildDuelRows(page, args, mapUrls, scope, limit, context = {}) {\n  const playerA = parsePlayerRef(args.playerA);\n  const playerB = parsePlayerRef(args.playerB);\n  const rows = [];\n\n  for (const mapUrl of mapUrls.slice(0, limit)) {\n    const mapRows = await readMatchMap(page, mapUrl);\n    const playerARow = findPlayer(mapRows, playerA.playerId);\n    const playerBRow = findPlayer(mapRows, playerB.playerId);\n    if (!playerARow || !playerBRow) continue;\n    const matrix = playerARow.team === playerBRow.team ? [] : await readPerformanceKillMatrix(page, mapUrl);\n    const direct = parseDirectDuel(matrix, playerARow.playerName, playerBRow.playerName);\n    rows.push(toMapRow(scope, mapUrl, playerARow, playerBRow, direct));","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/hltv/player-duel.js#L249-L285","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Increase the recentMaps argument to cover a longer window so the last encounter falls inside it","Verify both playerIds/slugs resolve to active HLTV profiles with recent matches","Check manually that the two players actually faced each other recently before calling","Handle EmptyResultError at the call site and report 'no encounter' as a valid outcome"],"exampleFix":"// before\nconst series = await findLastEncounterSeries(page, { playerA, playerB, recentMaps: 20 });\n// after\nlet series;\ntry {\n  series = await findLastEncounterSeries(page, { playerA, playerB, recentMaps: 20 });\n} catch (err) {\n  if (err instanceof EmptyResultError) series = null;\n  else throw err;\n}","handlingStrategy":"try-catch","validationCode":"// ensure window is wide enough before calling\nif (!Number.isInteger(recentMaps) || recentMaps < 50) recentMaps = 100;","typeGuard":"function hasRecentMaps(playerA) { return Number.isFinite(playerA?.playerId); }","tryCatchPattern":"try {\n  const series = await findLastEncounterSeries(page, { playerA, playerB, recentMaps });\n} catch (err) {\n  if (err instanceof EmptyResultError) return null; // no encounter is a valid answer\n  throw err;\n}","preventionTips":["Use a generous recentMaps window (e.g. 100) for rivals who meet rarely","Validate both playerId values resolve to active profiles first","Treat EmptyResultError as a legitimate 'no data' answer, not a crash","Log playerIds with the error to diagnose which ref is wrong"],"tags":["hltv","empty-result","no-data"],"backgroundTag":"empty-result-set","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}