jackwener/OpenCLI · error · CommandExecutionError
${label} request failed: ${err?.message ?? err}
Error message
${label} request failed: ${err?.message ?? err} What it means
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.
Source
Thrown at clis/semanticscholar/utils.js:99
}
/**
* Fetch with optional `SEMANTIC_SCHOLAR_API_KEY` header. Retries once on 429
* after a short pause; anonymous traffic hits the public ~100 req / 5 min
* cap, and a single retry covers the typical burst-then-cool-down case.
*/
export async function s2Fetch(url, label) {
const headers = { 'user-agent': UA, accept: 'application/json' };
const apiKey = process.env.SEMANTIC_SCHOLAR_API_KEY;
if (apiKey) headers['x-api-key'] = apiKey;
let resp;
let attempt = 0;
while (true) {
try {
resp = await fetch(url, { headers });
} catch (err) {
throw new CommandExecutionError(
`${label} request failed: ${err?.message ?? err}`,
'Check that api.semanticscholar.org is reachable from this network.',
);
}
if (resp.status === 429 && attempt === 0 && !apiKey) {
attempt += 1;
await new Promise(resolve => setTimeout(resolve, 1500));
continue;
}
break;
}
if (resp.status === 404) {
throw new EmptyResultError(label, `Semantic Scholar returned 404 for ${url}.`);
}
if (resp.status === 429) {
throw new CommandExecutionError(
`${label} returned HTTP 429 (rate limited)`,View on GitHub (pinned to 49907e53dc)
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.
Example fix
// before opencli semanticscholar search "bert" # fails: ENOTFOUND api.semanticscholar.org // after export HTTPS_PROXY=http://proxy.corp:8080 opencli semanticscholar search "bert"
Defensive patterns
Strategy: retry
Validate before calling
// preflight reachability check
const ok = await fetch('https://api.semanticscholar.org/graph/v1', { method: 'HEAD' })
.then(r => r.ok || r.status < 500).catch(() => false);
if (!ok) console.error('api.semanticscholar.org unreachable; check network/proxy'); Try / catch
async function withNetworkRetry(fn, attempts = 3) {
for (let i = 0; ; i++) {
try { return await fn(); }
catch (err) {
const transient = /request failed|ENOTFOUND|ECONNREFUSED|ETIMEDOUT|ECONNRESET/i.test(String(err.message));
if (!transient || i >= attempts - 1) throw err;
await new Promise(r => setTimeout(r, 2 ** i * 1000));
}
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Air-gapped CI runners; corporate proxies requiring configuration (HTTPS_PROXY / NODE_EXTRA_CA_CERTS); VPN not connected; transient ISP/DNS outages.
Related errors
- `${label} request failed: ${err?.message ?? err}`
- Failed to fetch Flomo memos: ${err instanceof Error ? err.me
- lobsters domain request failed: ${err?.message ?? err}
- ${label} request failed: ${err?.message ?? err}
- FETCH_ERROR
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/5adc61278698ea7d.
Report an issue: GitHub.