jackwener/OpenCLI · error · CommandExecutionError
Zhihu ${label} returned malformed JSON: ${payload.__malforme
Error message
Zhihu ${label} returned malformed JSON: ${payload.__malformedJson} What it means
This CommandExecutionError is thrown by fetchCommentPage when the in-browser fetch of a Zhihu comment endpoint returned a payload flagged with __malformedJson, meaning the HTTP body could not be parsed as JSON inside the page context. The library throws it early so the malformed raw text can be surfaced instead of crashing later on undefined fields. It wraps the parse error message from the evaluated fetch helper.
Source
Thrown at clis/zhihu/answer-comments-helpers.js:60
return { __httpStatus: response.status, __malformedJson: error instanceof Error ? error.message : String(error) };
}
const error = body?.error && typeof body.error === 'object' ? body.error : null;
const result = {
__httpStatus: response.status,
__errorCode: error?.code ?? body?.error_code ?? '',
__errorMessage: error?.message || body?.error_msg || '',
__needLogin: error?.need_login === true || body?.need_login === true,
};
return !response.ok || result.__errorCode || result.__errorMessage || result.__needLogin ? result : body;
}, url).catch((error) => {
throw new CommandExecutionError(
`Zhihu ${label} request failed: ${error instanceof Error ? error.message : String(error)}`,
'Try again later or rerun with -v for more detail.',
);
});
const payload = unwrapEvaluateResult(evaluated);
if (payload?.__malformedJson) {
throw new CommandExecutionError(`Zhihu ${label} returned malformed JSON: ${payload.__malformedJson}`);
}
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
throw new CommandExecutionError(`Zhihu ${label} returned a malformed payload`);
}
const status = payload.__httpStatus;
const code = String(payload.__errorCode || '');
if (status >= 400 || code || payload.__errorMessage || payload.__needLogin) {
if (code === '40362') {
throw new CommandExecutionError(
`Zhihu risk control blocked ${label} (40362): ${payload.__errorMessage || 'abnormal request'}`,
'Open the answer in the connected Chrome profile and retry later.',
);
}
if (status === 401 || status === 403 || code === '40353' || payload.__needLogin) {
throw new AuthRequiredError('www.zhihu.com', `Failed to fetch Zhihu ${label}`);
}
if (status === 404 && notFoundDetail) throw new EmptyResultError('zhihu answer-comments', notFoundDetail);
if (status >= 400) throw new CommandExecutionError(`Zhihu ${label} request failed (HTTP ${status})`);View on GitHub (pinned to 49907e53dc)
Solutions
- Rerun with -v to inspect the raw body captured in the malformed JSON detail
- Open the answer URL in the connected Chrome profile, complete any login/captcha, then retry
- Verify the answer URL/id is valid (the answer still exists and is public)
- Retry later — transient risk-control HTML interstitials often clear after a cooldown
Example fix
// before
const payload = unwrapEvaluateResult(evaluated); // payload.__malformedJson set -> throw
// after
// handle gracefully at call site:
try { const p = await fetchCommentPage(...); } catch (e) { log(e.message); /* fall back to browser-visible fetch */ } Defensive patterns
Strategy: try-catch
Validate before calling
const res = await fetch(url, {headers:{accept:'application/json'}}); const ct = res.headers.get('content-type')||''; if (!ct.includes('json')) throw new Error('non-JSON response: ' + ct); Type guard
function isJsonPayload(p){ return !!p && typeof p === 'object' && !Array.isArray(p) && !p.__malformedJson; } Try / catch
try { await fetchCommentPage(url); } catch (e) { if (String(e.message).includes('malformed JSON')) { /* open profile, complete login/captcha, retry */ } else throw e; } Prevention
- Send Accept: application/json on in-page fetches
- Detect HTML responses early by checking content-type before JSON.parse
- Keep the Chrome profile logged in to avoid login-page HTML
- Throttle requests to avoid anti-bot HTML interstitials
When it happens
Trigger: The browser evaluate returned an object whose __malformedJson property is set — i.e. Zhihu's endpoint responded with HTML (login page, anti-bot interstitial), an empty body, or invalid JSON instead of the expected JSON API response.
Common situations: Zhihu serving an HTML login/verification page instead of JSON; rate limiting returning an HTML block page; the answer URL being wrong so an HTML 404 page is returned; network middleware/proxy injecting HTML error pages.
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
- 1point3acres request failed: ${error?.message || error}
- 1point3acres request failed: HTTP ${res.status} ${res.status
- Barchart greeks request failed: HTTP ${data.status}${data.st
- Boss API request failed: ${message}
- coingecko categories returned malformed JSON: ${err?.message
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/0a47f901e5a30ccc.
Report an issue: GitHub.