jackwener/OpenCLI · warning · EmptyResultError

Lichess returned 404 for ${url}.

Error message

Lichess returned 404 for ${url}.

What it means

This EmptyResultError is thrown by `lichessFetch` when the Lichess API responds with HTTP 404, meaning the requested resource (usually a user or endpoint path) does not exist. The library treats 'not found' as an empty result rather than a hard failure.

Source

Thrown at clis/lichess/utils.js:70

    if (n > maxValue) {
        throw new ArgumentError(`lichess ${label} must be <= ${maxValue}`);
    }
    return n;
}

export async function lichessFetch(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 lichess.org is reachable from this network.',
        );
    }
    if (resp.status === 404) {
        throw new EmptyResultError(label, `Lichess returned 404 for ${url}.`);
    }
    if (resp.status === 429) {
        throw new CommandExecutionError(
            `${label} returned HTTP 429 (rate limited)`,
            'Lichess throttles anonymous traffic at ~60 req/min; back off and retry.',
        );
    }
    if (!resp.ok) {
        throw new CommandExecutionError(`${label} returned HTTP ${resp.status}`);
    }
    let body;
    try {
        body = await resp.json();
    }
    catch (err) {
        throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);
    }
    return body;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the username/resource exists on lichess.org — 404 usually means unknown user
  2. Correct the typo in the handle (it is embedded in the error URL)
  3. Handle EmptyResultError and prompt the user to check the name
  4. Confirm the API endpoint URL is current if you built it manually

Example fix

// before
const u = await lichessFetch(`${API}/user/${name}`, 'lichess user'); // 404 on typo
// after
if (!/^[A-Za-z0-9_-]{2,30}$/.test(name)) throw new Error('check username');
try { const u = await lichessFetch(`${API}/user/${encodeURIComponent(name)}`, 'lichess user'); }
catch (e) { if (e instanceof EmptyResultError) return null; throw e; }
Defensive patterns

Strategy: try-catch

Validate before calling

const HANDLE_RE = /^[A-Za-z0-9_-]{2,30}$/;
function assertExistingHandle(name) {
  const s = String(name ?? '').trim();
  if (!HANDLE_RE.test(s)) throw new TypeError(`suspicious handle: ${name}`);
  return s;
}
await user(assertExistingHandle(rawName));

Type guard

function isPlausibleHandle(v) {
  return typeof v === 'string' && /^[A-Za-z0-9_-]{2,30}$/.test(v.trim());
}

Try / catch

try {
  const profile = await user(name);
} catch (e) {
  if (e instanceof EmptyResultError) {
    console.warn(`No Lichess user "${name}" found (404). Check spelling.`);
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Any command routed through `lichessFetch` where the constructed URL 404s — most commonly a username that does not exist on Lichess (user endpoints return 404 for unknown handles), or a stale/renamed API path.

Common situations: Typos in the username; querying a deleted/never-existing account; hardcoding an outdated API URL after a Lichess API change; URL-encoding mistakes producing an invalid path.

Related errors


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