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

  1. Log what the parser actually returned to confirm the shape
  2. Update the parser's selectors for the current HLTV markup
  3. Upgrade the CLI if a newer version has fixed parsers for the redesign
  4. 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

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


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