{"record":{"id":"df81f43b58fc9ba8","repo":"jackwener/OpenCLI","slug":"chess-com-callback-returned-http-resp-status-fo","errorCode":null,"errorMessage":"Chess.com callback returned HTTP ${resp.status} for ${url}","messagePattern":"Chess\\.com callback returned HTTP (.+?) for (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/chess/game.js","lineNumber":102,"sourceCode":"        'eco', 'time_control', 'rated', 'ply_count', 'url',\n    ],\n    func: async (kwargs) => {\n        const { kind, id } = parseGameUrl(kwargs['game-url']);\n        const url = `${CALLBACK_BASE}/${kind}/game/${id}`;\n        let resp;\n        try {\n            resp = await fetch(url, { headers: { 'User-Agent': UA, accept: 'application/json' } });\n        } catch (error) {\n            throw new CommandExecutionError(`Failed to fetch Chess.com callback ${url}: ${error?.message || error}`);\n        }\n        if (!resp || typeof resp !== 'object') {\n            throw new CommandExecutionError(`Chess.com callback returned an invalid response object for ${url}`);\n        }\n        if (resp.status === 404) {\n            throw new EmptyResultError(`Chess.com has no ${kind} game with id ${id}`);\n        }\n        if (!resp.ok) {\n            throw new CommandExecutionError(`Chess.com callback returned HTTP ${resp.status} for ${url}`);\n        }\n        let payload;\n        try {\n            payload = await resp.json();\n        } catch (error) {\n            throw new CommandExecutionError(`Chess.com callback returned malformed JSON for ${url}: ${error?.message || error}`);\n        }\n        return [summarizeGame({ kind, id, payload })];\n    },\n});\n\nexport const __test__ = { parseGameUrl, summarizeGame };\n","sourceCodeStart":84,"sourceCodeEnd":115,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/chess/game.js#L84-L115","documentation":"After handling 404, any other non-OK response (resp.ok false) from the Chess.com callback endpoint throws CommandExecutionError with the HTTP status. This surfaces upstream API problems — rate limiting, 5xx outages, redirects to challenge pages — as an explicit command error instead of a confusing JSON parse failure.","triggerScenarios":"The fetch to https://www.chess.com/callback/{kind}/game/{id} returns any status other than 2xx/404: 403 (bot challenge/Cloudflare), 429 (rate limited), 5xx (Chess.com outage).","commonSituations":"Hammering the API in a loop without delays (429); Chess.com serving a bot-detection page to datacenter IPs (403); temporary Chess.com incidents (500/502/503).","solutions":["Inspect the status in the message and retry after a backoff for 429/5xx","Send a realistic User-Agent and avoid high request rates — the library already sets UA, so add spacing between calls","For persistent 403, run from a different network/IP or use the public pubsub API endpoints instead of the callback endpoint"],"exampleFix":"// before: naive loop\nfor (const id of ids) await getGame(id);\n// after: throttle + backoff\nfor (const id of ids) {\n  try { await getGame(id); }\n  catch (e) { if (/HTTP 429|HTTP 5/.test(e.message)) await sleep(5000); }\n  await sleep(1000);\n}","handlingStrategy":"retry","validationCode":"// no pre-call validation possible; monitor status before retrying\n// e.g. check https://status.chess.com or reduce request frequency","typeGuard":null,"tryCatchPattern":"async function withRetry(fn, attempts = 3) {\n  for (let i = 0; ; i++) {\n    try { return await fn(); }\n    catch (e) {\n      const m = /HTTP (\\d{3})/.exec(e.message || '');\n      const status = m ? Number(m[1]) : 0;\n      if (i < attempts - 1 && (status === 429 || status >= 500)) { await new Promise(r => setTimeout(r, 2 ** i * 1000)); continue; }\n      throw e;\n    }\n  }\n}","preventionTips":["Throttle requests (>=1s between calls) to avoid 429","Keep a realistic User-Agent on every request","Avoid datacenter IPs that trigger 403 bot challenges","Back off exponentially on 5xx instead of tight-looping"],"tags":["http","rate-limit","http-403","upstream-error"],"backgroundTag":"http-5xx-upstream-error","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}