jackwener/OpenCLI · error · CommandExecutionError
toutiao hot-board request failed: ${error?.message || error}
Error message
toutiao hot-board request failed: ${error?.message || error} What it means
The toutiao `hot` command fetches Toutiao's public hot-board JSON (hot-event/hot-board) via fetch(). This error wraps any exception thrown by fetch itself — DNS failure, connection refused/reset, TLS error, timeout/abort, or invalid URL — re-thrown as a CommandExecutionError with the underlying cause message appended. It means the HTTP request never completed, so no response object exists.
Source
Thrown at clis/toutiao/hot.js:38
strategy: Strategy.PUBLIC,
browser: false,
args: [
{ name: 'limit', type: 'int', default: 30, help: '返回条数 (1-50)' },
],
columns: ['rank', 'group_id', 'title', 'query', 'hot_value', 'label', 'url', 'image_url'],
func: async (kwargs) => {
const limit = parseHotLimit(kwargs?.limit, 30);
let resp;
try {
resp = await fetch(HOT_BOARD_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 hot-board request failed: ${error?.message || error}`);
}
if (!resp.ok) {
throw new CommandExecutionError(`toutiao hot-board failed: HTTP ${resp.status}`);
}
let payload;
try {
payload = await resp.json();
} catch (error) {
throw new CommandExecutionError(`toutiao hot-board returned malformed JSON: ${error?.message || error}`);
}
if (payload?.status && payload.status !== 'success') {
throw new CommandExecutionError(`toutiao hot-board returned status=${payload.status}`);
}
if (payload?.error || payload?.message) {
throw new CommandExecutionError(`toutiao hot-board returned error: ${payload.error || payload.message}`);
}
const list = Array.isArray(payload?.data) ? payload.data : [];
const rows = list.map(mapHotRow).filter(Boolean).slice(0, limit);View on GitHub (pinned to 49907e53dc)
Solutions
- Check basic network connectivity to the endpoint (curl -I with the same User-Agent/Referer headers) to confirm reachability.
- If 'fetch is not a function' appears, upgrade to Node 18+ or add a fetch polyfill (undici/node-fetch).
- Configure or disable proxy env vars (HTTPS_PROXY/NO_PROXY) so the request can route out; retry after transient failures.
- If toutiao.com is blocked from your region, run from a network that can reach it or supply an alternative mirror URL.
Example fix
// before
resp = await fetch(HOT_BOARD_URL, { headers });
// after — retry transient network failures
let resp;
for (let attempt = 0; attempt < 3; attempt++) {
try {
resp = await fetch(HOT_BOARD_URL, { headers });
break;
} catch (e) {
if (attempt === 2) throw new CommandExecutionError(`toutiao hot-board request failed: ${e?.message || e}`);
await new Promise(r => setTimeout(r, 500 * (attempt + 1)));
}
} Defensive patterns
Strategy: retry
Validate before calling
// verify the endpoint is reachable before invoking the command
curl -sS -o /dev/null -w '%{http_code}' \
-H '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' \
-H 'Referer: https://www.toutiao.com/' \
https://www.toutiao.com/hot-event/hot-board/
// also: node -e "console.log(typeof fetch)" # must print 'function' (Node 18+) Try / catch
try {
const rows = await toutiaoHot({ limit: 30 });
} catch (e) {
if (/request failed/.test(e.message)) {
// network-layer failure: check connectivity/proxy, retry with backoff
await sleep(1000);
return toutiaoHot({ limit: 30 });
}
throw e;
} Prevention
- Require Node 18+ so global fetch exists.
- Set HTTPS_PROXY/NO_PROXY correctly in environments behind proxies.
- Wrap scheduled scrapes with retry + exponential backoff for transient network errors.
- Pre-flight check connectivity to toutiao.com in CI or cron scripts before running.
When it happens
Trigger: Calling the `toutiao hot` command when the network to www.toutiao.com is unreachable (offline, DNS failure, firewall/GFW blocking), the request is aborted (timeout/AbortSignal), or HOT_BOARD_URL becomes invalid — fetch() rejects before resp.ok can be checked.
Common situations: Running the CLI offline or behind a proxy that refuses connections; corporate/GFW blocking of toutiao.com; Node <18 where global fetch is undefined (TypeError 'fetch is not a function'); transient connection resets on mobile/VPN networks; typo'd or redirected HOT_BOARD_URL in utils.js.
Related errors
- archive search request failed: ${error?.message || error}
- coingecko derivatives request failed: ${err?.message ?? err}
- coingecko trending request failed: ${error?.message || error
- FETCH_ERROR
- github-trending request failed: ${error?.message || error}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/2d3b14c57993276f.
Report an issue: GitHub.