{"record":{"id":"8ee5ff58f2ca8ece","repo":"jackwener/OpenCLI","slug":"chess-com-returned-404-for-url","errorCode":null,"errorMessage":"Chess.com returned 404 for ${url}","messagePattern":"Chess\\.com returned 404 for (.+?)","errorType":"exception","errorClass":"EmptyResultError","httpStatus":404,"severity":"warning","filePath":"clis/chess/utils.js","lineNumber":54,"sourceCode":"            `Invalid Chess.com game URL: \"${value}\"`,\n            'Expected https://www.chess.com/game/live/<id> or https://www.chess.com/game/daily/<id>.',\n        );\n    }\n    return { kind: m[1].toLowerCase(), id: m[2] };\n}\n\nexport async function chessApi(path, fetchImpl = fetch) {\n    const url = path.startsWith('http') ? path : `${API_BASE}${path}`;\n    let resp;\n    try {\n        resp = await fetchImpl(url, { headers: { 'User-Agent': UA, accept: 'application/json' } });\n    } catch (error) {\n        throw new CommandExecutionError(`Failed to fetch Chess.com API ${url}: ${error?.message || error}`);\n    }\n    if (!resp || typeof resp !== 'object') {\n        throw new CommandExecutionError(`Chess.com API returned an invalid response object for ${url}`);\n    }\n    if (resp.status === 404) throw new EmptyResultError(`Chess.com returned 404 for ${url}`);\n    if (!resp.ok) throw new CommandExecutionError(`Chess.com API returned HTTP ${resp.status} for ${url}`);\n    let payload;\n    try {\n        payload = await resp.json();\n    } catch (error) {\n        throw new CommandExecutionError(`Chess.com API returned malformed JSON for ${url}: ${error?.message || error}`);\n    }\n    if (!isPlainObject(payload)) {\n        throw new CommandExecutionError(`Chess.com API returned an unexpected payload shape for ${url}`);\n    }\n    return payload;\n}\n\n/** Pull rating + record fields out of a stats sub-object (`chess_rapid` etc). */\nexport function summarizeStats(stats, kind) {\n    const k = stats?.[kind];\n    if (!k) return null;\n    if (!isPlainObject(k)) {","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/chess/utils.js#L36-L72","documentation":"An EmptyResultError thrown when the Chess.com API responds with HTTP 404 for the requested URL. The library deliberately maps 404 to the empty-result family: the endpoint exists but no resource was found for that player/game/month, which callers usually want to treat as 'no data' rather than a hard failure.","triggerScenarios":"Querying /player/<username>/stats or monthly archives for a username that does not exist, a game id that does not exist, or a YYYY/MM archive month with no games for an existing player.","commonSituations":"Typo in the username; querying a player who closed/renamed their account; requesting a month before the account existed; stale game id from an old link.","solutions":["Double-check the username spelling (note validateUsername lowercases it first).","Confirm the player/game exists on chess.com in a browser.","Catch EmptyResultError in the caller and render a 'not found' message instead of failing.","For archives, derive valid YYYY/MM ranges from the player's joined date."],"exampleFix":"// before\nconst rows = await chessStats({ username: 'hikarru' }); // typo -> 404\n// after\ntry {\n  const rows = await chessStats({ username: 'hikaru' });\n} catch (e) {\n  if (e.name === 'EmptyResultError') return console.log('Player not found');\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Pre-check existence with the profile endpoint:\nconst profile = await chessApi(`/player/${encodeURIComponent(username)}`); // 404 here means user does not exist","typeGuard":"function isEmptyResult(e) {\n  return e instanceof Error && e.name === 'EmptyResultError' && /returned 404/.test(e.message);\n}","tryCatchPattern":"try {\n  const rows = await chessStats({ username });\n} catch (e) {\n  if (e.name === 'EmptyResultError') {\n    return console.log(`No Chess.com data found for ${username}.`);\n  }\n  throw e;\n}","preventionTips":["Verify usernames/ids on chess.com before batch queries.","Treat EmptyResultError as 'not found', not a crash.","Clamp archive months to the player's join date onward."],"tags":["http-404","not-found","empty-result","chess-com"],"backgroundTag":"http-404","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}