jackwener/OpenCLI · critical · CommandExecutionError

Failed to fetch Chess.com API ${url}: ${error?.message || er

Error message

Failed to fetch Chess.com API ${url}: ${error?.message || error}

What it means

A CommandExecutionError thrown when the fetch itself rejects — the HTTP request to the Chess.com API never completed. The original error message is embedded, and the failing URL is included for diagnosis. This happens before any HTTP status can be inspected.

Source

Thrown at clis/chess/utils.js:49

    const s = String(value ?? '').trim();
    if (!s) throw new ArgumentError('<game-url> is required');
    const m = s.match(GAME_URL_RE);
    if (!m) {
        throw new ArgumentError(
            `Invalid Chess.com game URL: "${value}"`,
            'Expected https://www.chess.com/game/live/<id> or https://www.chess.com/game/daily/<id>.',
        );
    }
    return { kind: m[1].toLowerCase(), id: m[2] };
}

export async function chessApi(path, fetchImpl = fetch) {
    const url = path.startsWith('http') ? path : `${API_BASE}${path}`;
    let resp;
    try {
        resp = await fetchImpl(url, { headers: { 'User-Agent': UA, accept: 'application/json' } });
    } catch (error) {
        throw new CommandExecutionError(`Failed to fetch Chess.com API ${url}: ${error?.message || error}`);
    }
    if (!resp || typeof resp !== 'object') {
        throw new CommandExecutionError(`Chess.com API returned an invalid response object for ${url}`);
    }
    if (resp.status === 404) throw new EmptyResultError(`Chess.com returned 404 for ${url}`);
    if (!resp.ok) throw new CommandExecutionError(`Chess.com API returned HTTP ${resp.status} for ${url}`);
    let payload;
    try {
        payload = await resp.json();
    } catch (error) {
        throw new CommandExecutionError(`Chess.com API returned malformed JSON for ${url}: ${error?.message || error}`);
    }
    if (!isPlainObject(payload)) {
        throw new CommandExecutionError(`Chess.com API returned an unexpected payload shape for ${url}`);
    }
    return payload;
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Check network connectivity and confirm https://api.chess.com is reachable (curl the URL).
  2. On Node <18, polyfill global fetch or upgrade Node so the default fetchImpl exists.
  3. Configure HTTP(S)_PROXY / agent settings if a corporate proxy is required.
  4. If you inject a custom fetchImpl, verify it is a working async function returning a Response-like object.

Example fix

// before
const stats = await chessApi('/player/hikaru/stats'); // Node 16: fetch is undefined
// after
import fetch from 'node-fetch';
globalThis.fetch ??= fetch;
const stats = await chessApi('/player/hikaru/stats');
Defensive patterns

Strategy: retry

Validate before calling

// Reachability pre-check before running the workflow:
const ok = await fetch('https://api.chess.com/pub/player/hikaru', { method: 'HEAD' })
  .then(() => true)
  .catch(() => false);
if (!ok) throw new Error('api.chess.com unreachable; check network/proxy');

Type guard

function isNetworkError(e) {
  return e instanceof Error && /Failed to fetch Chess.com API/.test(e.message);
}

Try / catch

async function withRetry(fn, { retries = 3, backoffMs = 1000 } = {}) {
  for (let i = 0; ; i++) {
    try { return await fn(); }
    catch (e) {
      if (!isNetworkError(e) || i >= retries) throw e;
      await new Promise((r) => setTimeout(r, backoffMs * 2 ** i));
    }
  }
}
const stats = await withRetry(() => chessApi('/player/hikaru/stats'));

Prevention

When it happens

Trigger: DNS resolution failure for api.chess.com, connection refused/timeout, TLS errors, offline network, or a custom fetchImpl injected into chessApi that throws (e.g. a stub not configured or a proxy rejecting the request).

Common situations: Corporate proxy or firewall blocking api.chess.com; no internet connection; Node without a global fetch (older Node <18, so fetch is undefined and calling it throws); VPN or DNS misconfiguration.

Related errors


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