{"record":{"id":"21184d90f922abac","repo":"jackwener/OpenCLI","slug":"lichess-returned-404-for-url","errorCode":null,"errorMessage":"Lichess returned 404 for ${url}.","messagePattern":"Lichess returned 404 for (.+?)\\.","errorType":"error_code","errorClass":"EmptyResultError","httpStatus":404,"severity":"warning","filePath":"clis/lichess/utils.js","lineNumber":70,"sourceCode":"    if (n > maxValue) {\n        throw new ArgumentError(`lichess ${label} must be <= ${maxValue}`);\n    }\n    return n;\n}\n\nexport async function lichessFetch(url, label) {\n    let resp;\n    try {\n        resp = await fetch(url, { headers: { 'user-agent': UA, accept: 'application/json' } });\n    }\n    catch (err) {\n        throw new CommandExecutionError(\n            `${label} request failed: ${err?.message ?? err}`,\n            'Check that lichess.org is reachable from this network.',\n        );\n    }\n    if (resp.status === 404) {\n        throw new EmptyResultError(label, `Lichess returned 404 for ${url}.`);\n    }\n    if (resp.status === 429) {\n        throw new CommandExecutionError(\n            `${label} returned HTTP 429 (rate limited)`,\n            'Lichess throttles anonymous traffic at ~60 req/min; back off and retry.',\n        );\n    }\n    if (!resp.ok) {\n        throw new CommandExecutionError(`${label} returned HTTP ${resp.status}`);\n    }\n    let body;\n    try {\n        body = await resp.json();\n    }\n    catch (err) {\n        throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);\n    }\n    return body;","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/lichess/utils.js#L52-L88","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the username/resource exists on lichess.org — 404 usually means unknown user","Correct the typo in the handle (it is embedded in the error URL)","Handle EmptyResultError and prompt the user to check the name","Confirm the API endpoint URL is current if you built it manually"],"exampleFix":"// before\nconst u = await lichessFetch(`${API}/user/${name}`, 'lichess user'); // 404 on typo\n// after\nif (!/^[A-Za-z0-9_-]{2,30}$/.test(name)) throw new Error('check username');\ntry { const u = await lichessFetch(`${API}/user/${encodeURIComponent(name)}`, 'lichess user'); }\ncatch (e) { if (e instanceof EmptyResultError) return null; throw e; }","handlingStrategy":"try-catch","validationCode":"const HANDLE_RE = /^[A-Za-z0-9_-]{2,30}$/;\nfunction assertExistingHandle(name) {\n  const s = String(name ?? '').trim();\n  if (!HANDLE_RE.test(s)) throw new TypeError(`suspicious handle: ${name}`);\n  return s;\n}\nawait user(assertExistingHandle(rawName));","typeGuard":"function isPlausibleHandle(v) {\n  return typeof v === 'string' && /^[A-Za-z0-9_-]{2,30}$/.test(v.trim());\n}","tryCatchPattern":"try {\n  const profile = await user(name);\n} catch (e) {\n  if (e instanceof EmptyResultError) {\n    console.warn(`No Lichess user \"${name}\" found (404). Check spelling.`);\n    return null;\n  }\n  throw e;\n}","preventionTips":["Double-check usernames against lichess.org before scripting lookups","encodeURIComponent the handle when building URLs manually","Treat 404/EmptyResultError as 'unknown user' and skip gracefully in batches","Keep API endpoint URLs in sync with current Lichess API docs"],"tags":["lichess","http-404","not-found","api"],"backgroundTag":"http-404-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}