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
- Resolve the correct map-stats URL first (e.g. via the function that returns 'hltv match map urls' / mapstatsid links) and pass that in
- Ensure the URL path ends with a trailing slash after the numeric mapstatsid followed by a slug
- 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
- Always source mapstatsid URLs from the library's own map-URL listing helpers
- Keep the trailing slash and slug in the URL path
- Add a preflight regex check on any URL you construct by hand
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
- match map parser requires a /stats/matches/mapstatsid/:id/:s
- id not a valid Grok conversation URL (got "${input}"); expec
- <train-no> must not be empty
- <train-no> "${trainNo}" does not look like a 12306 internal
- --from station must not be empty
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/c3d20589db9d0bdf.
Report an issue: GitHub.