jackwener/OpenCLI · error · CommandExecutionError
toutiao recommend returned malformed JSON: ${error?.message
Error message
toutiao recommend returned malformed JSON: ${error?.message || error} What it means
This CommandExecutionError is thrown when resp.json() fails while parsing the toutiao recommend response — the body was not valid JSON. The parse error message is embedded so developers can see whether it was an unexpected token, empty body, etc.
Source
Thrown at clis/toutiao/recommend.js:58
try {
resp = await fetch(url, {
headers: {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
Accept: 'application/json',
Referer: 'https://www.toutiao.com/',
},
});
} catch (error) {
throw new CommandExecutionError(`toutiao recommend request failed: ${error?.message || error}`);
}
if (!resp.ok) {
throw new CommandExecutionError(`toutiao recommend failed: HTTP ${resp.status}`);
}
let payload;
try {
payload = await resp.json();
} catch (error) {
throw new CommandExecutionError(`toutiao recommend returned malformed JSON: ${error?.message || error}`);
}
if (payload?.message && payload.message !== 'success') {
throw new CommandExecutionError(`toutiao recommend returned message=${payload.message}`);
}
if (!Array.isArray(payload?.data)) {
throw new CommandExecutionError('toutiao recommend returned a non-array data field');
}
const rows = payload.data.map(mapRecommendRow).filter(Boolean).slice(0, limit);
if (rows.length === 0) {
throw new EmptyResultError('toutiao recommend', `频道 ${category} 返回空列表。`);
}
// Re-rank (1..N) after filter so ranks are dense even if upstream had ads.
return rows.map((row, idx) => ({ ...row, rank: idx + 1 }));
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Dump the raw response body (resp.text()) once to see what upstream actually returned — usually it is an HTML block page.
- If it is an anti-bot page, add realistic headers/cookies or route through a different IP.
- Retry — truncated/corrupt bodies are often transient.
- Check whether a proxy or VPN in the path is mangling the response.
Example fix
// before
await recommend({ category: 'tech' });
// after
try {
await recommend({ category: 'tech' });
} catch (e) {
if (String(e.message).includes('malformed JSON')) {
console.error('Upstream returned non-JSON (likely anti-bot page).', e.message);
} else throw e;
} Defensive patterns
Strategy: try-catch
Try / catch
try {
return await recommend({ category });
} catch (e) {
if (String(e.message).includes('malformed JSON')) {
// upstream returned non-JSON (likely anti-bot page); retry or degrade
return [];
}
throw e;
} Prevention
- Inspect the raw body once when this recurs — usually an HTML block page.
- Keep request headers realistic to reduce anti-bot interception.
- Distinguish this from network errors: a 200 with junk body is an upstream/proxy issue.
- Retry transiently; persistent malformed bodies indicate IP blocking.
When it happens
Trigger: Calling 'toutiao recommend' when the upstream returns HTML (anti-bot challenge page), an empty body, truncated gzip content, or any non-JSON payload with a 2xx status.
Common situations: Upstream serving a CAPTCHA/verification HTML page with status 200; a transparent proxy intercepting and rewriting the response; CDN error pages; response body truncated by network issues.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — 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
- Reuters search returned a non-JSON body${detail}
- Zhihu answer detail returned malformed JSON: ${data.__malfor
- 12306 queryByTrainNo returned non-JSON body
- Failed to parse 12306 station_name.js: source string not fou
- archive search returned malformed JSON: ${error?.message ||
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/7c3b165b1b6f1a49.
Report an issue: GitHub.