jackwener/OpenCLI · error · CommandExecutionError
hltv match-map parser returned an unexpected shape
Error message
hltv match-map parser returned an unexpected shape
What it means
After gotoAndWait loads the map-stats page, readMatchMap runs page.evaluate() to scrape player rows into an array. If the browser-side serializer returns something other than an array (e.g. null/undefined because evaluation failed or the page was replaced), a CommandExecutionError with this message is thrown. It is a defensive postcondition on the parser's return shape.
Source
Thrown at clis/hltv/utils.js:601
dateTime,
teamScore: currentTeam === teamOne ? teamOneScore : teamTwoScore,
opponent,
opponentScore: currentTeam === teamOne ? teamTwoScore : teamOneScore,
headshots: kills.paren,
assists: assists.main,
flashAssists: assists.paren,
tradedDeaths: deaths.paren,
multiKills: numberFrom(textOf(tr, '.st-mks')),
clutches: numberFrom(textOf(tr, '.st-clutches')),
roundSwingPct: numberFrom(textOf(tr, '.st-roundSwing')),
},
url: playerUrl,
});
}
return rows;
}, { base: BASE, matchStatsId });
if (!Array.isArray(rows)) throw new CommandExecutionError('hltv match-map parser returned an unexpected shape');
if (rows.length === 0) throw new CommandExecutionError('hltv match-map parser found no player rows');
return assertRequiredFields(rows.map((row) => ({
matchStatsId: row.matchStatsId,
playerId: row.playerId,
playerName: row.playerName,
team: row.team,
kills: parseNumber(row.kills),
deaths: parseNumber(row.deaths),
adr: parseNumber(row.adr),
kastPct: parseNumber(row.kastPct),
rating: parseNumber(row.rating),
opKd: row.opKd,
details: row.details,
url: row.url,
})), 'hltv match-map', ['matchStatsId', 'playerId', 'playerName', 'team', 'url']);
}
View on GitHub (pinned to 49907e53dc)
Solutions
- Re-run with backoff; if the page was an anti-bot interstitial, retrying after the block clears usually yields a proper array
- Verify the URL actually renders the stats section by checking for '.stats-table.totalstats' in the loaded page
- Slow down request rate / rotate proxies if HLTV is serving guard pages
- Update the library if HLTV changed its page structure so the evaluate no longer completes normally
Example fix
// before
const rows = await readMatchMap(page, url); // throws on interstitial
// after
try {
const rows = await readMatchMap(page, url);
} catch (err) {
if (/unexpected shape/.test(err.message)) {
await sleep(5000);
return readMatchMap(page, url); // retry once
}
throw err;
} Defensive patterns
Strategy: try-catch
Try / catch
try {
const rows = await readMatchMap(page, mapstatsUrl);
} catch (err) {
if (/unexpected shape/.test(String(err?.message))) {
await sleep(5000);
return readMatchMap(page, mapstatsUrl); // retry — page may have been a guard page
}
throw err;
} Prevention
- Retry transient parse failures with backoff
- Watch for anti-bot/interstitial responses and slow down or rotate proxies
- Verify the loaded page contains '.stats-table.totalstats' before treating failures as data problems
When it happens
Trigger: page.evaluate returning non-array — typically when the page navigation was hijacked (login wall, Cloudflare/DDoS-guard interstitial, error page) or the execution context was destroyed mid-evaluation and the wrapper returned undefined.
Common situations: Scraping behind HLTV's anti-bot interstitial pages; running against a stale or crashed page target; proxy or network middlewares injecting HTML so the evaluate context differs; heavy rate-limiting causing the loaded document to not be a stats page.
Related errors
- Ctrip round-trip flight DOM extraction returned malformed ro
- Ctrip round-trip flight cards rendered but parser did not fi
- Ctrip round-trip flight rows were missing required airline/f
- Ctrip flight network capture returned malformed entries
- dianping search parser found no result-shaped shop cards
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/1edb0196fc4c4939.
Report an issue: GitHub.