{"record":{"id":"6dac3cd47ed12784","repo":"jackwener/OpenCLI","slug":"label-returned-http-resp-status-6dac3c","errorCode":null,"errorMessage":"${label} returned HTTP ${resp.status}","messagePattern":"(.+?) returned HTTP (.+?)","errorType":"http","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/lichess/utils.js","lineNumber":79,"sourceCode":"        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;\n}\n\n/** Format a lichess unix-ms timestamp as ISO date (YYYY-MM-DD). `null` when missing. */\nexport function formatTimestamp(ms) {\n    if (typeof ms !== 'number' || !Number.isFinite(ms) || ms <= 0) return null;\n    const d = new Date(ms);\n    if (Number.isNaN(d.getTime())) return null;\n    return d.toISOString();\n}","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/lichess/utils.js#L61-L97","documentation":"lichessFetch wraps all Lichess API calls and throws CommandExecutionError when the HTTP response status is not ok. The 429 rate-limit case is handled separately with a richer message; this generic branch covers every other non-2xx status (404, 403, 5xx, etc.). It signals the Lichess endpoint rejected the request for a reason other than rate limiting.","triggerScenarios":"Any lichessFetch call (via body and the lichess subcommands) where resp.ok is false and status !== 429 — e.g. requesting a non-existent user (404), hitting an endpoint that requires OAuth (403), or Lichess returning 5xx during incidents.","commonSituations":"Typing a wrong username in a lichess command; Lichess API outage or maintenance; calling an endpoint that now requires authentication after a Lichess API change; proxy/firewall injecting error responses.","solutions":["Read resp.status in the error context and check Lichess API docs for that code (404 = not found, 403 = forbidden, 5xx = server side).","Verify the username/ID/endpoint path passed to the command is correct.","Check https://status.lichess.org for outages if the status is 5xx.","Retry later if transient; if 403, obtain an OAuth token if the endpoint requires one."],"exampleFix":"// before\nconst games = await lichessFetch('/api/user/definitely-not-a-user');\n// after\nlet games;\ntry {\n  games = await lichessFetch('/api/user/existing-user');\n} catch (e) {\n  if (String(e.message).includes('HTTP 404')) throw new EmptyResultError('no such lichess user');\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"const m = /^lichess\\b/i.test(cmd) && /\\S+/.test(args[0] || '') ? args[0] : null;\nif (!m) throw new Error('supply a valid lichess username/endpoint argument');","typeGuard":"function isOkStatus(status) { return Number.isInteger(status) && status >= 200 && status < 300; }","tryCatchPattern":"try {\n  const data = await lichessFetch(path);\n} catch (e) {\n  const m = /HTTP (\\d{3})/.exec(e.message);\n  if (m) {\n    const status = Number(m[1]);\n    if (status >= 500 || status === 429) { /* retry with backoff */ }\n    else throw new Error(`lichess request failed: ${status}`);\n  } else throw e;\n}","preventionTips":["Validate usernames/IDs against known patterns before calling.","Check https://status.lichess.org before blaming your code on 5xx.","Use an OAuth token for endpoints that require authentication.","Distinguish 4xx (fix your input) from 5xx (retry later) in handling code."],"tags":["http","network","api"],"backgroundTag":"http-error-status","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}