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

  1. Verify network connectivity (curl the URL or ping the host)
  2. Check proxy environment variables (HTTPS_PROXY) and corporate CA configuration
  3. Retry — transient DNS/connection failures often resolve on retry
  4. If behind a firewall, allowlist the WeRead web origin
  5. 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

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


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/f2de05a19f49c16d. Report an issue: GitHub.