jackwener/OpenCLI · error · CliError
FETCH_ERROR
FETCH_ERROR
Error message
Sina Finance API HTTP ${res.status} What it means
The sinafinance news command fetches Sina Finance's 7x24 live-news API (app.cj.sina.com.cn/api/news/pc) with no auth. On any non-ok response it throws a CliError with code FETCH_ERROR, the HTTP status in the message, and a hint to check the network. It distinguishes transport-level rejection from the separate NOT_FOUND case (empty feed).
Source
Thrown at clis/sinafinance/news.js:48
domain: 'app.cj.sina.com.cn',
strategy: Strategy.PUBLIC,
browser: false,
args: [
{ name: 'limit', type: 'int', default: 20, help: 'Max results (max 50)' },
{ name: 'type', type: 'int', default: 0, help: 'News type: 0=全部 1=A股 2=宏观 3=公司 4=数据 5=市场 6=国际 7=观点 8=央行 9=其它' },
],
columns: ['id', 'time', 'content', 'views'],
func: async (args) => {
const limit = Math.max(1, Math.min(Number(args.limit), 50));
const apiTag = TYPE_MAP[args.type] ?? 0;
const params = new URLSearchParams({
page: '1',
size: String(limit),
tag: String(apiTag),
});
const res = await fetch(`https://app.cj.sina.com.cn/api/news/pc?${params}`);
if (!res.ok) {
throw new CliError('FETCH_ERROR', `Sina Finance API HTTP ${res.status}`, 'Check your network connection');
}
const json = await res.json();
const list = json?.result?.data?.feed?.list ?? [];
if (!list.length) {
throw new CliError('NOT_FOUND', 'No news found', 'Try a different type or increase limit');
}
return list.map((item) => ({
id: item.id ?? '',
time: item.create_time ?? '',
content: stripHtml(item.rich_text ?? ''),
views: item.view_num ?? 0,
}));
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Retry with exponential backoff, especially for 429/5xx.
- Check network connectivity and any proxy/VPN that may be blocked by Sina.
- Keep `size` within 1–50 as the command already caps it; avoid excessive polling frequency.
- Try a different `type`/tag in case a specific category endpoint is failing.
- Wait out Sina-side maintenance and verify the endpoint is still live.
Example fix
// before
const res = await fetch(`https://app.cj.sina.com.cn/api/news/pc?${params}`);
if (!res.ok) throw new CliError('FETCH_ERROR', `Sina Finance API HTTP ${res.status}`, 'Check your network connection');
// after: single retry with backoff before failing
let res = await fetch(`https://app.cj.sina.com.cn/api/news/pc?${params}`);
if (!res.ok && (res.status === 429 || res.status >= 500)) {
await new Promise(r => setTimeout(r, 1500));
res = await fetch(`https://app.cj.sina.com.cn/api/news/pc?${params}`);
}
if (!res.ok) throw new CliError('FETCH_ERROR', `Sina Finance API HTTP ${res.status}`, 'Check your network connection'); Defensive patterns
Strategy: retry
Validate before calling
const limit = Math.max(1, Math.min(Number(args.limit) || 20, 50));
const type = Number.isInteger(args.type) && args.type >= 0 && args.type <= 9 ? args.type : 0;
if (!Number.isFinite(limit) || limit < 1) throw new Error('limit must be 1-50'); Try / catch
try {
const feed = await fetchNews(limit, type);
} catch (err) {
if (err.code === 'FETCH_ERROR') {
const m = /HTTP (\d{3})/.exec(err.message);
if (m && (+m[1] === 429 || +m[1] >= 500)) return retryWithBackoff(() => fetchNews(limit, type), 3);
}
throw err;
} Prevention
- Poll at modest intervals; this public feed throttles aggressive clients.
- Keep `size` within 1–50 as the command enforces.
- Use retries with backoff for 429/5xx responses.
- Check network/proxy reachability to app.cj.sina.com.cn.
- Distinguish FETCH_ERROR (transport) from NOT_FOUND (empty feed) when handling.
When it happens
Trigger: fetch to https://app.cj.sina.com.cn/api/news/pc?page=1&size=N&tag=T returns 403 (WAF/blocked IP), 429 (throttled), or 5xx (Sina backend outage); also DNS/proxy failures would surface differently (network throw, not this error).
Common situations: Accessing from non-CN IPs that Sina's CDN throttles; bursts of polling requests hitting rate limits; Sina API maintenance windows; oversized `size` params triggering rejection.
Related errors
- ${label} returned HTTP ${resp.status}: ${summarizeApiError(p
- HTTP ${result.httpStatus} from /api/organizations
- ${label} returned HTTP ${res.status}
- HTTP_ERROR
- HTTP_ERROR
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/1b73443a8a01c03f.
Report an issue: GitHub.