jackwener/OpenCLI · error · CommandExecutionError
Zhihu column download returned malformed article fields
Error message
Zhihu column download returned malformed article fields
What it means
During `zhihu download` of a column article, requireArticle validates the shape of the data returned by the in-page extraction (via unwrapEvaluateResult): it must be a non-array object with string `title`, string `contentHtml`, and an array of string `imageUrls`. CommandExecutionError (code COMMAND_EXEC) is thrown when any field is missing or of the wrong type, guarding downstream export code from malformed page data.
Source
Thrown at clis/zhihu/download-helpers.js:116
for (const name of ['data-original', 'data-actualsrc', 'data-src']) img.removeAttribute(name);
if (!src) img.removeAttribute('src');
else {
img.setAttribute('src', src);
if (!seen.has(src)) {
seen.add(src);
imageUrls.push(src);
}
}
});
return { contentHtml: root.innerHTML, imageUrls };
}
function requireArticle(raw) {
const data = unwrapEvaluateResult(raw);
if (!data || typeof data !== 'object' || Array.isArray(data)
|| typeof data.title !== 'string' || typeof data.contentHtml !== 'string'
|| !Array.isArray(data.imageUrls) || !data.imageUrls.every((url) => typeof url === 'string')) {
throw new CommandExecutionError('Zhihu column download returned malformed article fields');
}
if (!data.contentHtml.trim()) {
throw new EmptyResultError('zhihu download', 'The Zhihu column article had no exportable content.');
}
return data;
}
export async function extractColumnArticle(page, target) {
await page.goto(target.url);
await page.wait(3);
const normalize = `(${normalizeContentImages.toString()})`;
const raw = await page.evaluate(`
(() => {
const content = document.querySelector('.Post-RichTextContainer, .RichText, .ArticleContent');
const normalized = ${normalize}(content?.innerHTML || '');
return {
title: document.querySelector('.Post-Title, h1.ContentItem-title, .ArticleTitle')?.textContent?.trim() || 'untitled',
author: document.querySelector('.AuthorInfo-name, .UserLink-link')?.textContent?.trim() || '',View on GitHub (pinned to 49907e53dc)
Solutions
- Log the raw value returned by the in-page extraction (before requireArticle) to see which field is missing/mistyped.
- Update the extraction script's selectors to the current Zhihu column article DOM so title/contentHtml/imageUrls are populated.
- Ensure the page is fully loaded before extraction (wait for the article content node) so fields are not undefined.
- Confirm unwrapEvaluateResult is receiving the data payload, not an error/exception envelope from the evaluate call.
Example fix
// before: assuming extraction always returns full shape
const data = await page.evaluate(extractScript);
exportArticle(data);
// after: pre-check before calling requireArticle
const data = await page.evaluate(extractScript);
if (!data || typeof data.contentHtml !== 'string') {
await page.wait(3); // content may not have mounted yet
}
const article = requireArticle(await page.evaluate(extractScript)); Defensive patterns
Strategy: type-guard
Validate before calling
const raw = await page.evaluate(extractScript);
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new Error('Extraction returned no article object'); Type guard
function isArticleData(v) {
return v != null && typeof v === 'object' && !Array.isArray(v)
&& typeof v.title === 'string'
&& typeof v.contentHtml === 'string'
&& Array.isArray(v.imageUrls) && v.imageUrls.every((u) => typeof u === 'string');
} Try / catch
try {
const article = requireArticle(await page.evaluate(extractScript));
} catch (e) {
if (e.code === 'COMMAND_EXEC' && /malformed article fields/i.test(e.message)) {
console.error('Zhihu DOM may have changed — dump raw extraction for inspection');
}
throw e;
} Prevention
- Wait for the article content node to mount before running the extraction script.
- When Zhihu updates its column pages, re-verify extraction selectors return title/contentHtml/imageUrls.
- Validate the evaluate result shape before passing it to export code.
When it happens
Trigger: The page.evaluate/extract script returns undefined, null, a non-serializable value, or an object whose title/contentHtml/imageUrls do not match the expected types — typically because Zhihu changed the column article DOM so the extraction selectors return undefined fields.
Common situations: Zhihu column pages redesigned so `contentHtml` comes back undefined; the extraction returning an array instead of an object; a lazy-loaded page where the script runs before content mounts; unwrapping a browser evaluate result that was an exception payload rather than data.
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.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- ${label} returned an unexpected payload shape; expected an o
- Booking.com extractor returned malformed items
- Booking.com extractor returned malformed hotel row
- dianping search parser found no result-shaped shop cards
- dianping search parser found result cards without shop_id va
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/ee4073244bf75716.
Report an issue: GitHub.