jackwener/OpenCLI · critical · CommandExecutionError

${label} request failed: ${err?.message ?? err}

Error message

${label} request failed: ${err?.message ?? err}

What it means

openalexFetch wraps all HTTP access to api.openalex.org and throws CommandExecutionError when the fetch itself rejects (network-level failure, before any HTTP status is seen). The message includes the labeled operation and the underlying error, with a hint to check reachability of api.openalex.org. This distinguishes transport failure from HTTP error statuses like 404 or 429.

Source

Thrown at clis/openalex/utils.js:87

        return `doi:${doiUrl[1]}`;
    }
    // 5) bare 10.xxxx/yyy DOI
    if (DOI_BARE.test(raw)) {
        return `doi:${raw}`;
    }
    throw new ArgumentError(
        `openalex work id "${value}" is not recognised`,
        'Use a Work id ("W2741809807"), a DOI ("10.7717/peerj.4375"), or a full openalex.org / doi.org URL.',
    );
}

export async function openalexFetch(url, label) {
    let resp;
    try {
        resp = await fetch(url, { headers: { 'user-agent': UA, accept: 'application/json' } });
    }
    catch (err) {
        throw new CommandExecutionError(
            `${label} request failed: ${err?.message ?? err}`,
            'Check that api.openalex.org is reachable from this network.',
        );
    }
    if (resp.status === 404) {
        throw new EmptyResultError(label, `OpenAlex returned 404 for ${url}.`);
    }
    if (resp.status === 429) {
        throw new CommandExecutionError(
            `${label} returned HTTP 429 (rate limited)`,
            'OpenAlex throttles unauthenticated traffic; wait a few seconds and retry, or set OPENALEX_MAILTO.',
        );
    }
    if (!resp.ok) {
        let detail = '';
        try {
            const text = await resp.text();
            const match = text.match(/"message"\s*:\s*"([^"]+)"/);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Check network connectivity and that https://api.openalex.org resolves/reachable (curl it)
  2. Configure proxy env vars (HTTPS_PROXY) if behind a corporate proxy
  3. Retry after a short wait if it was a transient drop; consider adding a timeout/retry wrapper
  4. Inspect the inner err.message in the error text for the specific socket/DNS cause

Example fix

// before
const works = await openalexSearch(q); // throws on any network blip
// after
const works = await withRetry(3, () => openalexSearch(q));
function withRetry(n, fn) {
  return fn().catch(e => n > 1 ? withRetry(n - 1, fn) : Promise.reject(e));
}
Defensive patterns

Strategy: retry

Try / catch

try {
  const data = await openalexFetch(url, 'openalex work');
} catch (e) {
  if (e.name === 'CommandExecutionError' && e.message.includes('request failed')) {
    // network-level failure: check connectivity/proxy, retry with backoff
    await sleep(1000);
    return openalexFetch(url, 'openalex work');
  }
  throw e;
}

Prevention

When it happens

Trigger: fetch() rejecting due to DNS failure, no route to host, TLS errors, connection refused/timeout, or an offline network while calling any openalex command (search, ref, etc.).

Common situations: Corporate proxy or firewall blocking api.openalex.org; VPN required but not connected; DNS misconfiguration; IPv6 issues; ephemeral network drops in CI.

Related errors


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