{"record":{"id":"4e1a9a03d658dbc5","repo":"jackwener/OpenCLI","slug":"manifestpath-must-point-to-a-json-array-exported-b","errorCode":null,"errorMessage":"manifestPath must point to a JSON array exported by grok/export","messagePattern":"manifestPath must point to a JSON array exported by grok/export","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/grok/export-utils.js","lineNumber":77,"sourceCode":"        if (!row || typeof row !== 'object' || Array.isArray(row)) {\n            throw new CommandExecutionError(`${label} returned a malformed row`, `Row ${index + 1} is not an object.`);\n        }\n        const id = String(row.id || '').trim().toLowerCase();\n        if (!GROK_CONVERSATION_ID_RE.test(id)) {\n            throw new CommandExecutionError(`${label} returned a malformed row`, `Row ${index + 1} is missing a valid Grok conversation id.`);\n        }\n        return {\n            id,\n            title: row.title == null || row.title === '' ? '' : String(row.title),\n            date: row.date == null || row.date === '' ? '' : String(row.date),\n            url: normalizeGrokUrl(row.url, id, (reason) => new CommandExecutionError(`${label} returned a malformed row`, reason)),\n        };\n    });\n}\n\nexport function normalizeManifestRows(rows) {\n    if (!Array.isArray(rows)) {\n        throw new ArgumentError('manifestPath', 'must point to a JSON array exported by grok/export');\n    }\n    return rows.map((row, index) => {\n        if (!row || typeof row !== 'object' || Array.isArray(row)) {\n            throw new ArgumentError('manifestPath', `row ${index + 1} must be an object`);\n        }\n        const id = String(row.id || '').trim().toLowerCase();\n        if (!GROK_CONVERSATION_ID_RE.test(id)) {\n            throw new ArgumentError('manifestPath', `row ${index + 1} is missing a valid Grok conversation id`);\n        }\n        return {\n            id,\n            title: row.title == null || row.title === '' ? '' : String(row.title),\n            date: row.date == null || row.date === '' ? '' : String(row.date),\n            url: normalizeGrokUrl(row.url, id, (reason) => new ArgumentError('manifestPath', `row ${index + 1}: ${reason}`)),\n        };\n    });\n}\n","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/grok/export-utils.js#L59-L95","documentation":"normalizeManifestRows reads rows loaded from a --manifestPath JSON file. It first checks that the parsed file is an array; this ArgumentError is thrown when it is not (object, null, string, number, etc.). The library only accepts the exact format `grok/export` produces: a top-level JSON array of conversation rows.","triggerScenarios":"Passing a manifestPath whose file parses (JSON.parse succeeded) to something other than an array: e.g. an object {conversations: [...]}, a JSONL file (invalid or single-object), an empty/garbage file, or a variable holding undefined/null passed directly; detail: 'must point to a JSON array exported by grok/export'.","commonSituations":"Pointing --manifestPath at the wrong file (a config JSON or package.json); the export script was updated to wrap rows in an envelope object; the file was written by JSON.stringify of a single object; a newer/older CLI version changed the manifest schema.","solutions":["Regenerate the manifest with `grok/export` so the file is a top-level JSON array.","Check the first non-whitespace character of the file: `[` means array; `{` means you have an envelope object — unwrap the rows field and pass the array instead.","If you must consume an enveloped export, extract rows = parsed.conversations (or the actual array property) and normalize that.","Verify the correct file is being passed to --manifestPath (easy to point at a different JSON artifact)."],"exampleFix":"// before\nconst parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));\nnormalizeManifestRows(parsed); // parsed = { conversations: [...] } → throws\n\n// after\nconst parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));\nconst rows = Array.isArray(parsed) ? parsed : parsed.conversations;\nnormalizeManifestRows(rows);","handlingStrategy":"validation","validationCode":"const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));\nif (!Array.isArray(parsed)) {\n  throw new Error(`--manifestPath must be a JSON array; got ${parsed === null ? 'null' : typeof parsed}`);\n}","typeGuard":"function isManifestFile(content) {\n  const parsed = JSON.parse(content);\n  return Array.isArray(parsed);\n}","tryCatchPattern":"import { ArgumentError } from '@jackwener/opencli/errors';\ntry {\n  const rows = normalizeManifestRows(parsed);\n} catch (err) {\n  if (err instanceof ArgumentError && /JSON array/.test(err.message)) {\n    console.error('manifestPath file is not a grok/export JSON array — regenerate with grok/export or unwrap the rows field.');\n  } else throw err;\n}","preventionTips":["Always generate manifests with grok/export; never hand-write them.","Quick-check the file starts with '[' before passing it via --manifestPath.","If your tooling wraps exports in an envelope, unwrap the rows array first."],"tags":["validation","cli-argument","json-schema","grok-export"],"backgroundTag":"invalid-cli-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}