jackwener/OpenCLI · error · CommandExecutionError

${label} returned a malformed row

Error message

${label} returned a malformed row

What it means

normalizeConversationRows validates rows scraped from the Grok conversation list before export. This error is thrown when a row is present in the array but is not a plain object (null, undefined, a primitive, or an Array). The library refuses to guess or coerce such a row, since it cannot read row.id/title/date/url from it.

Source

Thrown at clis/grok/export-utils.js:60

    }
    const host = parsed.hostname.toLowerCase();
    const match = parsed.pathname.match(/^\/c\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\/?$/i);
    if (parsed.protocol !== 'https:' || (host !== 'grok.com' && !host.endsWith('.grok.com')) || !match) {
        throw makeError(`invalid url for conversation ${id}`);
    }
    if (match[1].toLowerCase() !== id) {
        throw makeError(`url id mismatch for conversation ${id}`);
    }
    return `https://grok.com/c/${id}`;
}

export function normalizeConversationRows(rows, label) {
    if (!Array.isArray(rows)) {
        throw new CommandExecutionError(`${label} returned malformed rows`, 'Expected rows to be an array.');
    }
    return rows.map((row, index) => {
        if (!row || typeof row !== 'object' || Array.isArray(row)) {
            throw new CommandExecutionError(`${label} returned a malformed row`, `Row ${index + 1} is not an object.`);
        }
        const id = String(row.id || '').trim().toLowerCase();
        if (!GROK_CONVERSATION_ID_RE.test(id)) {
            throw new CommandExecutionError(`${label} returned a malformed row`, `Row ${index + 1} is missing a valid Grok conversation id.`);
        }
        return {
            id,
            title: row.title == null || row.title === '' ? '' : String(row.title),
            date: row.date == null || row.date === '' ? '' : String(row.date),
            url: normalizeGrokUrl(row.url, id, (reason) => new CommandExecutionError(`${label} returned a malformed row`, reason)),
        };
    });
}

export function normalizeManifestRows(rows) {
    if (!Array.isArray(rows)) {
        throw new ArgumentError('manifestPath', 'must point to a JSON array exported by grok/export');
    }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Find the offending index (reported as `Row N is not an object.` in the error detail) and inspect the source array at rows[N-1].
  2. Fix the upstream scraper/evaluate payload so every element is an object with id, title, date, url fields before calling normalizeConversationRows.
  3. Filter out non-object entries yourself first: rows = rows.filter(r => r && typeof r === 'object' && !Array.isArray(r)).
  4. If you only have a manifest JSON file, verify it is an array of objects via `node -e "const d=require('./m.json'); d.forEach((r,i)=>{if(!r||typeof r!=='object'||Array.isArray(r)) throw i+1})"`.

Example fix

// before
const rows = await page.evaluate(() => scrapedRows); // scrapedRows may contain nulls
const valid = normalizeConversationRows(rows, 'grok/list');

// after
const rows = (await page.evaluate(() => scrapedRows)) ?? [];
const cleaned = rows.filter((r) => r && typeof r === 'object' && !Array.isArray(r));
const valid = normalizeConversationRows(cleaned, 'grok/list');
Defensive patterns

Strategy: validation

Validate before calling

function isRowArray(rows) {
  return Array.isArray(rows) && rows.every((r) => r && typeof r === 'object' && !Array.isArray(r));
}
if (!isRowArray(rows)) throw new Error('conversation rows must be an array of objects');

Type guard

function isConversationRow(row) {
  return typeof row === 'object' && row !== null && !Array.isArray(row);
}

Try / catch

import { CommandExecutionError } from '@jackwener/opencli/errors';
try {
  const rows = normalizeConversationRows(raw, 'grok/list');
} catch (err) {
  if (err instanceof CommandExecutionError) {
    // err.detail tells you which row index failed
    console.error(`Grok export rows malformed: ${err.message} — ${err.detail}`);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling normalizeConversationRows(rows, label) where rows is an array containing at least one element that is null, undefined, a primitive (string/number/boolean), or an array; the error message includes the 1-based row index in `Row ${index + 1} is not an object.`

Common situations: A page-eval extraction script returned null placeholders for conversations that were deleted mid-scrape; a JSON scrape file was hand-edited or truncated; a version change in Grok's DOM scraper produced different shapes; someone passed a top-level JSON object keyed by id instead of an array of rows.

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/8d713844803e7653. Report an issue: GitHub.