{"record":{"id":"5adc61278698ea7d","repo":"jackwener/OpenCLI","slug":"label-request-failed-err-message-err-5adc61","errorCode":null,"errorMessage":"${label} request failed: ${err?.message ?? err}","messagePattern":"(.+?) request failed: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/semanticscholar/utils.js","lineNumber":99,"sourceCode":"}\n\n/**\n * Fetch with optional `SEMANTIC_SCHOLAR_API_KEY` header. Retries once on 429\n * after a short pause; anonymous traffic hits the public ~100 req / 5 min\n * cap, and a single retry covers the typical burst-then-cool-down case.\n */\nexport async function s2Fetch(url, label) {\n    const headers = { 'user-agent': UA, accept: 'application/json' };\n    const apiKey = process.env.SEMANTIC_SCHOLAR_API_KEY;\n    if (apiKey) headers['x-api-key'] = apiKey;\n\n    let resp;\n    let attempt = 0;\n    while (true) {\n        try {\n            resp = await fetch(url, { headers });\n        } catch (err) {\n            throw new CommandExecutionError(\n                `${label} request failed: ${err?.message ?? err}`,\n                'Check that api.semanticscholar.org is reachable from this network.',\n            );\n        }\n        if (resp.status === 429 && attempt === 0 && !apiKey) {\n            attempt += 1;\n            await new Promise(resolve => setTimeout(resolve, 1500));\n            continue;\n        }\n        break;\n    }\n\n    if (resp.status === 404) {\n        throw new EmptyResultError(label, `Semantic Scholar returned 404 for ${url}.`);\n    }\n    if (resp.status === 429) {\n        throw new CommandExecutionError(\n            `${label} returned HTTP 429 (rate limited)`,","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/semanticscholar/utils.js#L81-L117","documentation":"s2Fetch wraps the underlying fetch call; when the request to api.semanticscholar.org throws at the network level (DNS failure, connection refused/reset, TLS error, timeout), it rethrows as CommandExecutionError prefixed with the request label and the original error message, advising to check network reachability. It converts low-level network exceptions into the CLI's uniform error type.","triggerScenarios":"Any semanticscholar command (search, paper, citations, recommendations) executed while offline; DNS unable to resolve api.semanticscholar.org; firewall/proxy blocking outbound 443; TLS interception with an untrusted cert causing fetch to reject.","commonSituations":"Air-gapped CI runners; corporate proxies requiring configuration (HTTPS_PROXY / NODE_EXTRA_CA_CERTS); VPN not connected; transient ISP/DNS outages.","solutions":["Verify reachability: `curl -I https://api.semanticscholar.org/graph/v1/paper/search?query=test`.","Fix DNS or connect the network/VPN, then retry.","Configure proxy environment variables (HTTPS_PROXY) and, for TLS interception, NODE_EXTRA_CA_CERTS with the corporate CA.","In code, catch CommandExecutionError and retry with backoff for transient network errors."],"exampleFix":"// before\nopencli semanticscholar search \"bert\"   # fails: ENOTFOUND api.semanticscholar.org\n// after\nexport HTTPS_PROXY=http://proxy.corp:8080\nopencli semanticscholar search \"bert\"","handlingStrategy":"retry","validationCode":"// preflight reachability check\nconst ok = await fetch('https://api.semanticscholar.org/graph/v1', { method: 'HEAD' })\n    .then(r => r.ok || r.status < 500).catch(() => false);\nif (!ok) console.error('api.semanticscholar.org unreachable; check network/proxy');","typeGuard":null,"tryCatchPattern":"async function withNetworkRetry(fn, attempts = 3) {\n    for (let i = 0; ; i++) {\n        try { return await fn(); }\n        catch (err) {\n            const transient = /request failed|ENOTFOUND|ECONNREFUSED|ETIMEDOUT|ECONNRESET/i.test(String(err.message));\n            if (!transient || i >= attempts - 1) throw err;\n            await new Promise(r => setTimeout(r, 2 ** i * 1000));\n        }\n    }\n}","preventionTips":["Check outbound HTTPS access / DNS resolution in CI before running API-dependent steps.","Configure HTTPS_PROXY and NODE_EXTRA_CA_CERTS on corporate networks.","Wrap CLI invocations in a retry-with-backoff helper for transient network errors.","Monitor DNS/VPN health; cache results to reduce dependence on live connectivity."],"tags":["network","dns","connectivity"],"backgroundTag":"connection-refused","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}