jackwener/OpenCLI · error · CommandExecutionError

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

Error message

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

What it means

juejinFetch wraps every outbound `fetch` to api.juejin.cn in a try/catch and rethrows any network-level failure (DNS, TCP, TLS, timeout, abort) as a CommandExecutionError. The original error's message is appended so the caller can see the underlying cause. It means the HTTP request never completed — the server response was never received.

Source

Thrown at clis/juejin/utils.js:99

/**
 * POST JSON to a Juejin endpoint. The API returns `{ err_no, err_msg, data }`;
 * a non-zero `err_no` is surfaced as a typed `CommandExecutionError`.
 */
export async function juejinFetch(path, body, label, method = 'POST') {
    const url = `${JUEJIN_API_BASE}${path}`;
    let resp;
    try {
        const init = {
            method,
            headers: { 'user-agent': UA, accept: 'application/json' },
        };
        if (method === 'POST') {
            init.headers['content-type'] = 'application/json';
            init.body = JSON.stringify(body ?? {});
        }
        resp = await fetch(url, init);
    } catch (err) {
        throw new CommandExecutionError(
            `${label} request failed: ${err?.message ?? err}`,
            'Check that api.juejin.cn is reachable from this network.',
        );
    }
    if (resp.status === 429) {
        throw new CommandExecutionError(
            `${label} returned HTTP 429 (rate limited)`,
            'Juejin throttles bursty traffic; wait a few seconds and retry.',
        );
    }
    if (!resp.ok) {
        throw new CommandExecutionError(`${label} returned HTTP ${resp.status}`);
    }
    let payload;
    try {
        payload = await resp.json();
    } catch (err) {
        throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify basic connectivity: `curl -I https://api.juejin.cn` — if this fails, fix DNS/proxy/firewall first.
  2. If behind a corporate proxy, set HTTPS_PROXY / HTTP_PROXY environment variables so Node's fetch can route through it.
  3. Check that the machine has working DNS (`nslookup api.juejin.cn`); add a resolver or hosts entry if needed.
  4. Retry later if the network to Chinese endpoints is degraded (e.g. use a VPN with China egress).
  5. Read the appended `err?.message` in the error text to identify the exact low-level cause (ENOTFOUND, ECONNREFUSED, ECONNRESET, CERT_...).

Example fix

// before (no connectivity config)
$ opencli juejin recommend
CommandExecutionError: juejin recommend request failed: getaddrinfo api.juejin.cn ENOTFOUND

// after (export proxy / fix DNS first)
$ export HTTPS_PROXY=http://corp-proxy:8080
$ opencli juejin recommend
rank 1 ...
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight reachability check
async function juejinReachable() {
  try {
    const r = await fetch('https://api.juejin.cn', { method: 'HEAD', signal: AbortSignal.timeout(5000) });
    return true; // any HTTP response means the host is reachable
  } catch {
    return false;
  }
}
if (!(await juejinReachable())) throw new Error('api.juejin.cn unreachable; check network/proxy/DNS');

Type guard

function isFetchNetworkError(err) {
  return err instanceof Error && (
    err.cause != null ||
    /ENOTFOUND|ECONNREFUSED|ECONNRESET|ETIMEDOUT|UND_ERR|CERT/.test(String(err.message))
  );
}

Try / catch

try {
  const payload = await juejinFetch(path, body, label);
} catch (err) {
  if (err instanceof CommandExecutionError && /request failed/.test(err.message)) {
    console.error(`Network problem reaching Juejin: ${err.message}. Fix connectivity or set HTTPS_PROXY.`);
    process.exitCode = 2; // transient/network class
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: The `fetch(url, init)` call inside juejinFetch rejects: DNS resolution failure for api.juejin.cn, connection refused/timed out, TLS handshake failure, or the request was aborted. Any adapter command (recommend feed, hot list, etc.) that goes through juejinFetch can produce this.

Common situations: Running the CLI offline or on a network that blocks api.juejin.cn (common outside China, where Juejin may be slow or firewalled); corporate proxies intercepting TLS; IPv6/DNS misconfiguration; Node fetch agent issues; firewalls dropping the connection mid-request.

Related errors


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