jackwener/OpenCLI · error · CommandExecutionError
${label} request failed: HTTP ${resp.status}
Error message
${label} request failed: HTTP ${resp.status} What it means
After the fetch succeeds, fetchJson checks resp.ok; any non-2xx HTTP status (403, 404, 429, 5xx) throws CommandExecutionError '<label> request failed: HTTP <status>'. The server answered but rejected or failed the request.
Source
Thrown at clis/weread/book-search.js:88
}
if (pathParts.length !== 3) {
return '';
}
return url.toString();
}
async function fetchJson(url, label) {
let resp;
try {
resp = await fetch(url.toString(), {
headers: { 'User-Agent': WEREAD_UA },
});
}
catch (error) {
throw new CommandExecutionError(`${label} request failed: ${error instanceof Error ? error.message : String(error)}`);
}
if (!resp.ok) {
throw new CommandExecutionError(`${label} request failed: HTTP ${resp.status}`);
}
try {
return await resp.json();
}
catch {
throw new CommandExecutionError(`${label} returned invalid JSON`);
}
}
async function fetchText(url, label) {
let resp;
try {
resp = await fetch(url.toString(), {
headers: { 'User-Agent': WEREAD_UA },
});
}
catch (error) {
throw new CommandExecutionError(`${label} request failed: ${error instanceof Error ? error.message : String(error)}`);View on GitHub (pinned to 49907e53dc)
Solutions
- Read the status code in the message: 403/429 → slow down or wait; 404 → endpoint changed; 5xx → retry later
- Add exponential backoff on 429/5xx responses
- Reduce request frequency or batch size
- Update the CLI if WeRead changed the endpoint path
- Check with curl -I using the same User-Agent to reproduce outside the tool
Example fix
// before (no status handling)
const data = await fetchJson(url, 'WeRead book search');
// after (backoff on 429/5xx)
try {
const data = await fetchJson(url, 'WeRead book search');
} catch (e) {
if (/HTTP (429|5\d\d)/.test(e.message)) { await sleep(2000); /* retry */ }
else throw e;
} Defensive patterns
Strategy: retry
Validate before calling
// Optional pre-flight status check
const head = await fetch(url, { method: 'HEAD', headers: { 'User-Agent': WEREAD_UA } });
if (head.status === 429) await sleep(2000); // back off before the real request Type guard
null
Try / catch
try {
const data = await fetchJson(url, 'WeRead book search');
} catch (e) {
const m = e.message.match(/HTTP (\d{3})/);
if (m) {
const status = Number(m[1]);
if (status === 429 || status >= 500) { /* retry with exponential backoff */ }
else if (status === 403) { console.error('Blocked/rate-limited; slow down or authenticate.'); }
}
throw e;
} Prevention
- Rate-limit your own requests (throttle/queue) to avoid 429s
- Use exponential backoff on 429 and 5xx responses
- Pin and update the CLI when WeRead changes endpoints (watch for 404s)
- Test the endpoint with curl -I using the same User-Agent when diagnosing
When it happens
Trigger: WeRead returns 403 (anti-bot/rate limiting or blocked User-Agent), 404 (endpoint moved), 429 (too many requests), or 5xx (server outage) for the /web/search/global call.
Common situations: Aggressive scripted querying triggers rate limiting, the API surface changes or is deprecated, regional blocking, or WeRead's WAF flags the CLI's User-Agent.
Related errors
- 12306 queryByTrainNo returned HTTP ${resp.status}
- 1point3acres request failed: HTTP ${res.status} ${res.status
- archive snapshots failed: HTTP ${resp.status}
- ${label} returned HTTP ${resp.status} (${url})
- Instagram private publish ${stage} failed: ${response.status
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/99d5024cb1946f56.
Report an issue: GitHub.