jackwener/OpenCLI · error · CommandExecutionError
${context} returned malformed message rows.
Error message
${context} returned malformed message rows. What it means
assertDiscordMessageRowsBelongToTarget iterates every message row and requires each to be a non-null, non-array object. Anything else (null, a string, an array) means the scraper returned structurally broken data, so it throws CommandExecutionError.
Source
Thrown at clis/discord-app/utils.js:600
}
export async function listDiscordThreads(page, limit) {
return requireRowsWithFields(
requireArrayEvaluateResult(await page.evaluate(buildListThreadsScript(limit)), 'Discord thread list'),
['Thread', 'guild_id', 'channel_id', 'thread_id', 'url'],
'Discord thread list',
);
}
export function assertDiscordMessageRowsBelongToTarget(rows, target, context = 'Discord read') {
if (!target) return rows;
const expectedChannelId = String(target.thread_id || target.channel_id || '');
if (!expectedChannelId) {
throw new CommandExecutionError(`${context} target is missing a stable channel/thread id.`);
}
for (const row of rows) {
if (!row || typeof row !== 'object' || Array.isArray(row)) {
throw new CommandExecutionError(`${context} returned malformed message rows.`);
}
const actualChannelId = row.channel_id == null || row.channel_id === '' ? '' : String(row.channel_id);
if (!actualChannelId) {
throw new CommandExecutionError(
`${context} could not verify returned message target.`,
`Expected channel/thread id ${expectedChannelId}, but the message row did not include channel_id.`,
);
}
if (actualChannelId && actualChannelId !== expectedChannelId) {
throw new CommandExecutionError(
`${context} returned messages from the wrong Discord target.`,
`Expected channel/thread id ${expectedChannelId}, saw ${actualChannelId}.`,
);
}
}
return rows;
}
View on GitHub (pinned to 49907e53dc)
Solutions
- Filter out non-object rows before calling: rows.filter(r => r && typeof r === 'object' && !Array.isArray(r)).
- Update/patch the message scraper so every emitted row is an object with channel_id and id fields.
- Check the Discord app DOM state — re-open the channel and retry if the UI was mid-render.
- Report/inspect upstream scraper output with "opencli discord-app messages -f json" to see the malformed payload.
Example fix
// before assertDiscordMessageRowsBelongToTarget(rows, target); // rows contains nulls // after const clean = rows.filter((r) => r && typeof r === 'object' && !Array.isArray(r)); assertDiscordMessageRowsBelongToTarget(clean, target);
Defensive patterns
Strategy: type-guard
Validate before calling
const bad = rows.findIndex(r => !r || typeof r !== 'object' || Array.isArray(r));
if (bad !== -1) throw new Error(`Row ${bad} is not a message object`); Type guard
function isMessageRow(r) { return r !== null && typeof r === 'object' && !Array.isArray(r); } Try / catch
try { assertDiscordMessageRowsBelongToTarget(rows, target, ctx); } catch (e) { if (String(e.message).includes('malformed message rows')) { rows = rows.filter(isMessageRow); return assertDiscordMessageRowsBelongToTarget(rows, target, ctx); } throw e; } Prevention
- Sanitize scraper output (drop null/primitive/array entries) before verification.
- Keep the extractor in sync with Discord DOM changes.
- Inspect raw JSON output when reads start failing after UI updates.
When it happens
Trigger: A row in the rows array passed to assertDiscordMessageRowsBelongToTarget is null, a primitive, or an Array — e.g. the DOM scraper emitted placeholder/null entries when no messages rendered.
Common situations: Reading messages from an empty channel where the scraper returns [null]; a Discord UI update changing selectors so the extractor returns raw strings; bugs in a custom row extractor.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- ${context} could not verify returned message target. Expecte
- ${context} target is missing a stable channel/thread id.
- ${context} returned messages from the wrong Discord target.
- ${label} returned an unexpected payload shape; expected an o
- Bilibili comments reply ${index + 1} was malformed
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/7fa45c608449f9a9.
Report an issue: GitHub.