jackwener/OpenCLI · error · ArgumentError

series resolution requires a /stats/matches/mapstatsid/:id/:

Error message

series resolution requires a /stats/matches/mapstatsid/:id/:slug URL

What it means

resolveStatsSeriesUrlFromMap() only accepts HLTV map-stats URLs of the form /stats/matches/mapstatsid/:id/:slug. Before doing anything it normalizes the input and tests url.pathname against that regex; if it does not match it throws ArgumentError. This is a fail-fast guard because series resolution navigates to a map-stats page and scrapes the series link, which is meaningless for other URL shapes.

Source

Thrown at clis/hltv/utils.js:501

    const out = [];
    for (const a of document.querySelectorAll('a[href*="/stats/matches/mapstatsid/"]')) {
      const href = new URL(a.getAttribute('href'), payload.base);
      href.search = '';
      href.hash = '';
      const key = href.pathname.match(/mapstatsid\/(\d+)\//)?.[1];
      if (!key || seen.has(key)) continue;
      seen.add(key);
      out.push(href.toString());
    }
    return out;
  }, { base: BASE });
  return assertRows(links, 'hltv match map urls');
}

export async function resolveStatsSeriesUrlFromMap(page, mapstatsUrl) {
  const url = normalizeMatchUrl(mapstatsUrl);
  if (!/^\/stats\/matches\/mapstatsid\/\d+\//.test(url.pathname)) {
    throw new ArgumentError('series resolution requires a /stats/matches/mapstatsid/:id/:slug URL');
  }

  await gotoAndWait(page, url, 'a[href*="/stats/matches/"]', 'hltv match series link page');
  const seriesUrl = await page.evaluate((payload) => {
    for (const a of document.querySelectorAll('a[href*="/stats/matches/"]')) {
      const href = new URL(a.getAttribute('href'), payload.base);
      href.search = '';
      href.hash = '';
      if (/^\/stats\/matches\/\d+\//.test(href.pathname)) return href.toString();
    }
    return null;
  }, { base: BASE });

  return seriesUrl ?? url.toString();
}

export async function readMatchMap(page, match) {
  const url = normalizeMatchUrl(match);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Resolve the correct map-stats URL first (e.g. via the function that returns 'hltv match map urls' / mapstatsid links) and pass that in
  2. Ensure the URL path ends with a trailing slash after the numeric mapstatsid followed by a slug
  3. Inspect the input string before calling; log it and confirm it matches /^\/stats\/matches\/mapstatsid\/\d+\//

Example fix

// before
await resolveStatsSeriesUrlFromMap(page, 'https://www.hltv.org/matches/2368101/natus-vincere-vs-faZe');
// after
await resolveStatsSeriesUrlFromMap(page, 'https://www.hltv.org/stats/matches/mapstatsid/73681/natus-vincere-vs-faze-map1');
Defensive patterns

Strategy: validation

Validate before calling

function isMapStatsUrl(input) {
  const u = new URL(input, 'https://www.hltv.org');
  return /^\/stats\/matches\/mapstatsid\/\d+\//.test(u.pathname);
}
if (!isMapStatsUrl(mapstatsUrl)) throw new Error('expected a /stats/matches/mapstatsid/:id/:slug URL');
await resolveStatsSeriesUrlFromMap(page, mapstatsUrl);

Type guard

function isMapStatsUrl(v) {
  try {
    const u = new URL(String(v), 'https://www.hltv.org');
    return /^\/stats\/matches\/mapstatsid\/\d+\//.test(u.pathname);
  } catch { return false; }
}

Try / catch

try {
  const seriesUrl = await resolveStatsSeriesUrlFromMap(page, mapstatsUrl);
} catch (err) {
  if (err instanceof ArgumentError && /series resolution requires/.test(err.message)) {
    console.error('Bad mapstats URL:', mapstatsUrl);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling resolveStatsSeriesUrlFromMap(page, mapstatsUrl) with a match-page URL (/stats/matches/:id/:slug), a player/event stats URL, a bare mapstatsid like 'https://www.hltv.org/stats/matches/mapstatsid/73681' without a trailing slash + slug, or any arbitrary string normalizeMatchUrl accepts.

Common situations: Passing a full match URL instead of a per-map stats URL (e.g. output of a match listing rather than resolveMatchMapUrls); constructing the URL by hand and omitting the trailing '/'; older HLTV URL formats or redirects that dropped the slug and trailing slash.

Related errors


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