jackwener/OpenCLI · error · CommandExecutionError
${label} request failed: ${error instanceof Error ? error.me
Error message
${label} request failed: ${error instanceof Error ? error.message : String(error)} What it means
fetchJson performs an HTTP GET with a WeRead User-Agent and wraps low-level fetch failures (network errors) in CommandExecutionError with the '<label> request failed:' prefix. This is thrown when the request never completes — DNS failure, connection refused/reset, TLS errors, or timeouts — before any HTTP status is received.
Source
Thrown at clis/weread/book-search.js:85
const pathParts = url.pathname.split('/').filter(Boolean);
if (url.protocol !== 'https:' || url.hostname !== 'weread.qq.com' || pathParts[0] !== 'web' || pathParts[1] !== 'reader' || !pathParts[2]) {
return '';
}
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 },
});View on GitHub (pinned to 49907e53dc)
Solutions
- Verify network connectivity (curl the URL or ping the host)
- Check proxy environment variables (HTTPS_PROXY) and corporate CA configuration
- Retry — transient DNS/connection failures often resolve on retry
- If behind a firewall, allowlist the WeRead web origin
- Inspect the inner error message after 'request failed:' to identify the root cause
Example fix
// before (no retry, hard fail)
const data = await fetchJson(url, 'WeRead book search');
// after (retry transient failures)
for (let attempt = 1; attempt <= 3; attempt++) {
try { return await fetchJson(url, 'WeRead book search'); }
catch (e) { if (attempt === 3) throw e; await sleep(500 * attempt); }
} Defensive patterns
Strategy: retry
Validate before calling
// Reachability probe before the real call
const probe = await fetch(WEREAD_WEB_ORIGIN, { method: 'HEAD' }).catch(() => null);
if (!probe) throw new Error('WeRead origin unreachable; check network/VPN/proxy'); Type guard
null
Try / catch
try {
const data = await fetchJson(url, 'WeRead book search');
} catch (e) {
if (e instanceof CommandExecutionError && e.message.includes('request failed:') && !e.message.includes('HTTP')) {
// network-layer failure: retry with backoff
for (let i = 1; i <= 3; i++) { await sleep(500 * 2 ** i); /* retry */ }
} else throw e;
} Prevention
- Wrap all network calls in retry-with-backoff helpers
- Check VPN/proxy environment (HTTPS_PROXY, corporate CA) before running in restricted networks
- Distinguish network failures from HTTP status failures by inspecting the message
- Prefer resolving the hostname once (dns lookup) to catch DNS issues early
When it happens
Trigger: The machine is offline, DNS cannot resolve the WeRead host, a proxy/firewall blocks the connection, fetch() rejects (ECONNREFUSED, ENOTFOUND, ETIMEDOUT, certificate errors), or an invalid URL string produces a throw inside the fetch call.
Common situations: Corporate proxies with MITM certificates, VPN required for access, Wi-Fi captive portals, IPv6 misconfiguration, or the WeRead endpoint being temporarily unreachable.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- ${label} request failed: ${outcome.detail}
- medium tag request failed: ${err?.message ?? err}
- 12306 queryByTrainNo returned HTTP ${resp.status}
- 12306 queryByTrainNo returned non-JSON body
- 12306 ${endpoint} returned non-JSON body
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/f2de05a19f49c16d.
Report an issue: GitHub.