jackwener/OpenCLI · error · CliError
FETCH_ERROR
FETCH_ERROR
Error message
FETCH_ERROR: HTTP ${resp.status} for ${path} What it means
Thrown by fetchWebApi in clis/weread/utils.js when a public WeRead web API call (https://weread.qq.com/web/*) returns a non-2xx HTTP status. It is a CliError with code FETCH_ERROR and a hint that the API may be temporarily unavailable. This covers all public endpoints used by browser-free commands like search and ranking.
Source
Thrown at clis/weread/utils.js:114
poll();
}))
`;
}
/**
* Fetch a public WeRead web endpoint (Node.js direct fetch).
* Used by search and ranking commands (browser: false).
*/
export async function fetchWebApi(path, params) {
const url = new URL(`${WEB_API}${path}`);
if (params) {
for (const [k, v] of Object.entries(params))
url.searchParams.set(k, v);
}
const resp = await fetch(url.toString(), {
headers: { 'User-Agent': WEREAD_UA },
});
if (!resp.ok) {
throw new CliError('FETCH_ERROR', `HTTP ${resp.status} for ${path}`, 'WeRead API may be temporarily unavailable');
}
try {
return await resp.json();
}
catch {
throw new CliError('PARSE_ERROR', `Invalid JSON response for ${path}`, 'WeRead may have returned an HTML error page');
}
}
/**
* Fetch a private WeRead API endpoint with cookies extracted from the browser.
* The HTTP request itself runs in Node.js to avoid page-context CORS failures.
*
* Cookies are collected from both the API subdomain (i.weread.qq.com) and the
* main domain (weread.qq.com). WeRead may set auth cookies as host-only on
* weread.qq.com, which won't match i.weread.qq.com in a URL-based lookup.
*/
export async function fetchPrivateApi(page, path, params) {
const url = new URL(`${API}${path}`);View on GitHub (pinned to 49907e53dc)
Solutions
- Retry with exponential backoff — transient 5xx/429 is the most common cause.
- Check the status: 403/429 → slow request rate, add browser-like headers, or supply cookies from a logged-in session; 404 → update the endpoint path after a WeRead API change; 5xx → wait for server recovery.
- Verify the endpoint manually: curl -A '<UA>' 'https://weread.qq.com/web/search/global?keyword=x' and inspect the body.
- Catch CliError with code 'FETCH_ERROR' in scripts and fall back to the HTML scraping path (loadSearchHtmlEntries).
- Check weread.qq.com status in a browser to rule out a full outage.
Example fix
// before
const data = await fetchWebApi('/search/global', { keyword: query });
// after
let data;
try {
data = await fetchWebApi('/search/global', { keyword: query });
} catch (e) {
if (e.code === 'FETCH_ERROR' && /HTTP (429|5\d\d)/.test(e.message)) {
await new Promise(r => setTimeout(r, 2000));
data = await fetchWebApi('/search/global', { keyword: query });
} else throw e;
} Defensive patterns
Strategy: retry
Validate before calling
// Health probe of the public API before batch usage
const r = await fetch('https://weread.qq.com/web/search/global?keyword=ping', { headers: { 'User-Agent': WEREAD_UA } });
if (!r.ok) console.warn(`weread web API unhealthy (HTTP ${r.status})`); Try / catch
try {
const data = await callWereadCommand();
} catch (e) {
if (e.code === 'FETCH_ERROR' && /HTTP \d{3}/.test(e.message)) {
const status = Number(/HTTP (\d{3})/.exec(e.message)[1]);
if (status === 429 || status >= 500) return withBackoffRetry(callWereadCommand);
throw e;
}
throw e;
} Prevention
- Add exponential backoff retries for 429/5xx statuses
- Rate-limit scripted calls to /web/* endpoints
- Catch on CliError.code rather than message text for stable handling
- Re-verify endpoint paths after WeRead web deploys (404s indicate route changes)
When it happens
Trigger: Any fetchWebApi call (e.g. /search/global with {keyword}) where resp.ok is false: 403/429 WAF or rate-limit responses, 404 after WeRead route changes, 5xx server errors, 30x followed to an error page.
Common situations: Rate limiting after scripted bulk queries; WeRead deploying new API paths; edge/CDN errors (502/504 from the qq.com CDN); anti-bot challenges returning 403 to non-browser fetches.
Related errors
- WeRead search page request failed: HTTP ${resp.status}
- coingecko derivatives returned HTTP ${resp.status}
- HTTP_ERROR
- hf models failed: HTTP ${resp.status}
- HTTP ${probe.httpStatus} from Jike users/profile
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/c606a60636036aca.
Report an issue: GitHub.