jackwener/OpenCLI · error · CommandExecutionError
${command} parser returned an unexpected shape
Error message
${command} parser returned an unexpected shape What it means
assertRows validates that a command's parser returned an array before further processing; if the parsed value is not an array it throws CommandExecutionError('<command> parser returned an unexpected shape'). It guards against HLTV DOM changes that make the parser return an object, null, or undefined.
Source
Thrown at clis/hltv/utils.js:852
if (!Array.isArray(matrix)) return [];
return matrix;
}
export async function gotoAndWait(page, url, selector, label) {
try {
await page.goto(url.toString(), { waitUntil: 'domcontentloaded', settleMs: 1000, timeout: 20000 });
await page.wait({ selector, timeout: 15000 });
} catch (error) {
if (/timeout/i.test(String(error?.message ?? error))) {
throw new TimeoutError(label, 15);
}
throw new CommandExecutionError(`${label} failed: ${error?.message ?? error}`);
}
}
export function assertRows(rows, command) {
if (!Array.isArray(rows)) throw new CommandExecutionError(`${command} parser returned an unexpected shape`);
if (rows.length === 0) throw new EmptyResultError(command, 'No rows were found in the visible HLTV page');
return rows;
}
export function assertRequiredFields(rows, command, fields) {
assertRows(rows, command);
for (const [index, row] of rows.entries()) {
for (const field of fields) {
if (row?.[field] === null || row?.[field] === undefined || row?.[field] === '') {
throw new CommandExecutionError(`${command} parser returned row ${index + 1} without required ${field}`);
}
}
}
return rows;
}
View on GitHub (pinned to 49907e53dc)
Solutions
- Log what the parser actually returned to confirm the shape
- Update the parser's selectors for the current HLTV markup
- Upgrade the CLI if a newer version has fixed parsers for the redesign
- Wrap the call in try/catch for CommandExecutionError and degrade gracefully
Example fix
// before
const rows = parseMatches(doc);
assertRows(rows, 'matches');
// after
const parsed = parseMatches(doc);
if (!Array.isArray(parsed)) {
console.warn('HLTV markup changed; matches parser returned', typeof parsed);
}
const rows = assertRows(parsed, 'matches'); Defensive patterns
Strategy: type-guard
Validate before calling
const parsed = parseRows(doc);
if (!Array.isArray(parsed)) {
throw new Error(`parser returned ${typeof parsed}, expected array`);
} Type guard
function isRowArray(value) {
return Array.isArray(value) && value.every(v => v !== null && typeof v === 'object');
} Try / catch
try {
const rows = assertRows(parsed, command);
} catch (err) {
if (err.name === 'CommandExecutionError' && /unexpected shape/.test(err.message)) {
console.error(`${command}: HLTV markup may have changed; got non-array from parser`);
return [];
}
throw err;
} Prevention
- Always Array.isArray-check parser output before consuming it
- Pin/upgrade the CLI version when HLTV redesigns its pages
- Add a smoke test per command that asserts a non-empty row array
- Log raw parser output on failure for faster diagnosis
When it happens
Trigger: A parse function returns anything other than an array — e.g. page.evaluate returns undefined after an HLTV markup change, or a parser bug returns a single object instead of an array.
Common situations: HLTV redesigns a page so selectors match nothing and the parser silently returns null/undefined; a newly added command's parser has a bug.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- ${command} parser returned row ${index + 1} without required
- YouTube video metadata is missing membersOnly
- Barchart greeks returned an unreadable options payload${data
- PARSE_ERROR
- dianping search parser found result cards without shop_id va
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/1c0a74a33b7035c1.
Report an issue: GitHub.