jackwener/OpenCLI · error · CommandExecutionError
Malformed ${draftType} draft payload
Error message
Malformed ${draftType} draft payload What it means
readDraftEntries validates that the in-page script's payload contains an entries array. If payload.ok was true but payload.entries is missing or not an Array, it throws CommandExecutionError with 'Malformed <draftType> draft payload'. This is a contract check against the browser-side result.
Source
Thrown at clis/xiaohongshu/draft-utils.js:132
return {
ok: true,
entries: allRows.map((row, index) => ({ key: allKeys[index] ?? index, row })),
};
} catch (error) {
return { ok: false, error: String(error && error.message || error) };
}
})()
`;
}
export async function readDraftEntries(page, draftType) {
const storeName = STORE_NAME_MAP[draftType];
const payload = unwrapBrowserResult(await page.evaluate(draftReadScript(storeName)));
if (!payload?.ok) {
throw new CommandExecutionError(payload?.error || `Failed to read ${draftType} drafts`);
}
if (!Array.isArray(payload.entries)) {
throw new CommandExecutionError(`Malformed ${draftType} draft payload`);
}
return payload.entries;
}
export function draftNotFound(id, draftType, command) {
return new EmptyResultError(
command,
`Draft ${id} was not found in ${draftType} drafts. Run opencli xiaohongshu drafts --type ${draftType} to list current ids.`,
);
}
View on GitHub (pinned to 49907e53dc)
Solutions
- Inspect the actual payload shape by evaluating draftReadScript(storeName) in DevTools on the drafts page
- Update draftReadScript to always return { ok: true, entries: [...] }
- Confirm the logged-in account actually has the draft store present; empty stores should still return []
- Re-check STORE_NAME_MAP mapping matches the current site store names
Example fix
// before (in-page script)
return { ok: true, entries: store.all() };
// after (guarantee array)
const all = store.all ? store.all() : [];
return { ok: true, entries: Array.isArray(all) ? all : [all] }; Defensive patterns
Strategy: type-guard
Validate before calling
const payload = unwrapBrowserResult(await page.evaluate(draftReadScript(storeName)));
if (!payload?.ok || !Array.isArray(payload.entries)) throw new Error('draft payload malformed'); Type guard
function hasEntries(p) { return !!p && typeof p === 'object' && p.ok === true && Array.isArray(p.entries); } Try / catch
try {
const entries = await readDraftEntries(page, draftType);
} catch (err) {
if (err instanceof CommandExecutionError && err.message.includes('Malformed')) {
// dump raw payload for debugging, update draftReadScript to normalize to array
} else throw err;
} Prevention
- Always return { ok:true, entries: [...] } from the in-page script, coercing to array
- Pin/verify the site's store schema after site updates
- Add a DevTools smoke test of draftReadScript output
When it happens
Trigger: page.evaluate(draftReadScript(storeName)) returns { ok: true } but entries is undefined, null, or a non-array (e.g. an object or single item) because the in-page script returned the wrong shape.
Common situations: Site script changes altering the draft store schema, a partial/empty store returning undefined, or a hand-edited draftReadScript that returns the store value directly instead of wrapping it in an entries array.
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
- Failed to read ${draftType} drafts
- ${webHost} feed: unexpected items payload shape
- Unexpected 12306 probe: ${JSON.stringify(probe)}
- Waiting for 12306 tk auth cookie
- 12306 ${endpoint} returned an unexpected payload shape
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/747cd8242deaf23e.
Report an issue: GitHub.