jackwener/OpenCLI · error · ArgumentError
match map parser requires a /stats/matches/mapstatsid/:id/:s
Error message
match map parser requires a /stats/matches/mapstatsid/:id/:slug URL
What it means
readMatchMap() parses a single map's stats page and requires the input to be a map-stats URL (/stats/matches/mapstatsid/:id/:slug). It normalizes the match argument and throws ArgumentError if the pathname does not match that pattern. This guard exists because the parser also extracts the numeric matchStatsId from the URL and navigates directly to the map page.
Source
Thrown at clis/hltv/utils.js:521
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);
if (!/^\/stats\/matches\/mapstatsid\/\d+\//.test(url.pathname)) {
throw new ArgumentError('match map parser requires a /stats/matches/mapstatsid/:id/:slug URL');
}
const matchStatsId = extractIdFromUrl(url.toString(), 'matchStats');
await gotoAndWait(page, url, '.stats-section.stats-match, .stats-table.totalstats', 'hltv match map page');
const rows = await page.evaluate((payload) => {
const clean = (value) => String(value ?? '').replace(/\s+/g, ' ').trim();
const cleanLines = (value) => String(value ?? '').split('\n').map((line) => clean(line)).filter(Boolean);
const numberFrom = (value) => {
const match = String(value ?? '').replace(/,/g, '').match(/-?\d+(?:\.\d+)?/);
return match ? Number(match[0]) : null;
};
const textOf = (root, selector) => clean(root.querySelector(selector)?.textContent);
const splitMainParen = (value) => {
const match = clean(value).match(/^(-?\d+(?:\.\d+)?)\s*(?:\(([-\d.]+)\))?/);
return { main: match ? Number(match[1]) : null, paren: match?.[2] !== undefined ? Number(match[2]) : null };
};
const infoLines = cleanLines(document.querySelector('.match-info-box')?.innerText);View on GitHub (pinned to 49907e53dc)
Solutions
- Pass a mapstatsid URL, e.g. from resolveMatchMapUrls()/resolveStatsSeriesUrlFromMap() output
- Verify the path matches /stats/matches/mapstatsid/<digits>/... including the trailing slash and slug
- If you only have a match ID, first navigate the match page flow to obtain the mapstatsid URLs, then call readMatchMap for each
Example fix
// before await readMatchMap(page, 'https://www.hltv.org/stats/matches/92734/natus-vincere-vs-faze'); // after await readMatchMap(page, 'https://www.hltv.org/stats/matches/mapstatsid/73681/natus-vincere-vs-faze-map1');
Defensive patterns
Strategy: validation
Validate before calling
function requireMapStatsUrl(match) {
const u = new URL(String(match), 'https://www.hltv.org');
if (!/^\/stats\/matches\/mapstatsid\/\d+\//.test(u.pathname)) {
throw new Error(`readMatchMap needs a mapstatsid URL, got: ${u.pathname}`);
}
return u.toString();
}
await readMatchMap(page, requireMapStatsUrl(match)); Type guard
function isMapStatsInput(v) {
try {
return /^\/stats\/matches\/mapstatsid\/\d+\//.test(new URL(String(v), 'https://www.hltv.org').pathname);
} catch { return false; }
} Try / catch
try {
const map = await readMatchMap(page, match);
} catch (err) {
if (err instanceof ArgumentError && /match map parser requires/.test(err.message)) {
console.error('Pass a /stats/matches/mapstatsid/:id/:slug URL, not:', match);
} else throw err;
} Prevention
- Distinguish match URLs (/matches/:id) from map stats URLs (/stats/matches/mapstatsid/:id) in your pipeline
- Normalize inputs through one helper that asserts the mapstatsid shape
- When iterating maps of a match, use the mapstatsid links collected from the match/series page
When it happens
Trigger: Calling readMatchMap(page, match) with a regular match URL (/matches/:id/:slug), a series stats URL (/stats/matches/:id/:slug), an ID-only string, or a URL with a trailing slash missing after the numeric ID.
Common situations: Confusing the public match URL with the per-map stats URL (these are different HLTV pages); reusing a URL collected from a series page instead of the mapstatsid links; hand-building the URL and forgetting the slug/trailing slash.
Related errors
- series resolution requires a /stats/matches/mapstatsid/:id/:
- 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/455e9f8d39f1baac.
Report an issue: GitHub.