{"record":{"id":"f2de05a19f49c16d","repo":"jackwener/OpenCLI","slug":"label-request-failed-error-instanceof-error","errorCode":null,"errorMessage":"${label} request failed: ${error instanceof Error ? error.message : String(error)}","messagePattern":"(.+?) request failed: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/weread/book-search.js","lineNumber":85,"sourceCode":"    const pathParts = url.pathname.split('/').filter(Boolean);\n    if (url.protocol !== 'https:' || url.hostname !== 'weread.qq.com' || pathParts[0] !== 'web' || pathParts[1] !== 'reader' || !pathParts[2]) {\n        return '';\n    }\n    if (pathParts.length !== 3) {\n        return '';\n    }\n    return url.toString();\n}\n\nasync function fetchJson(url, label) {\n    let resp;\n    try {\n        resp = await fetch(url.toString(), {\n            headers: { 'User-Agent': WEREAD_UA },\n        });\n    }\n    catch (error) {\n        throw new CommandExecutionError(`${label} request failed: ${error instanceof Error ? error.message : String(error)}`);\n    }\n    if (!resp.ok) {\n        throw new CommandExecutionError(`${label} request failed: HTTP ${resp.status}`);\n    }\n    try {\n        return await resp.json();\n    }\n    catch {\n        throw new CommandExecutionError(`${label} returned invalid JSON`);\n    }\n}\n\nasync function fetchText(url, label) {\n    let resp;\n    try {\n        resp = await fetch(url.toString(), {\n            headers: { 'User-Agent': WEREAD_UA },\n        });","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/weread/book-search.js#L67-L103","documentation":"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.","triggerScenarios":"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.","commonSituations":"Corporate proxies with MITM certificates, VPN required for access, Wi-Fi captive portals, IPv6 misconfiguration, or the WeRead endpoint being temporarily unreachable.","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"],"exampleFix":"// before (no retry, hard fail)\nconst data = await fetchJson(url, 'WeRead book search');\n// after (retry transient failures)\nfor (let attempt = 1; attempt <= 3; attempt++) {\n  try { return await fetchJson(url, 'WeRead book search'); }\n  catch (e) { if (attempt === 3) throw e; await sleep(500 * attempt); }\n}","handlingStrategy":"retry","validationCode":"// Reachability probe before the real call\nconst probe = await fetch(WEREAD_WEB_ORIGIN, { method: 'HEAD' }).catch(() => null);\nif (!probe) throw new Error('WeRead origin unreachable; check network/VPN/proxy');","typeGuard":"null","tryCatchPattern":"try {\n  const data = await fetchJson(url, 'WeRead book search');\n} catch (e) {\n  if (e instanceof CommandExecutionError && e.message.includes('request failed:') && !e.message.includes('HTTP')) {\n    // network-layer failure: retry with backoff\n    for (let i = 1; i <= 3; i++) { await sleep(500 * 2 ** i); /* retry */ }\n  } else throw e;\n}","preventionTips":["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"],"tags":["network","http","command-execution-error"],"backgroundTag":"http-request-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}