{"record":{"id":"5965448bb5145d7f","repo":"jackwener/OpenCLI","slug":"chess-com-callback-payload-is-missing-stable-game","errorCode":null,"errorMessage":"Chess.com callback payload is missing stable game summary fields","messagePattern":"Chess\\.com callback payload is missing stable game summary fields","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/chess/game.js","lineNumber":47,"sourceCode":"        throw new CommandExecutionError('Chess.com callback returned malformed player metadata');\n    }\n    const players = payload.players || {};\n    const byColor = {};\n    for (const slot of ['top', 'bottom']) {\n        const p = players[slot];\n        if (p !== undefined && !isPlainObject(p)) {\n            throw new CommandExecutionError('Chess.com callback returned malformed player metadata');\n        }\n        if (p?.color) byColor[p.color] = p;\n    }\n    const white = byColor.white || {};\n    const black = byColor.black || {};\n    const headers = g.pgnHeaders || {};\n    const whiteName = stringOrEmpty(white.username) || stringOrEmpty(headers.White);\n    const blackName = stringOrEmpty(black.username) || stringOrEmpty(headers.Black);\n    const result = stringOrEmpty(headers.Result);\n    if (!whiteName || !blackName || !result) {\n        throw new CommandExecutionError('Chess.com callback payload is missing stable game summary fields');\n    }\n    const headerDate = stringOrEmpty(headers.Date);\n    return {\n        kind,\n        game_id: id,\n        date: headerDate ? headerDate.replace(/\\./g, '-') : formatDate(g.endTime),\n        white: whiteName,\n        white_rating: scalarOrEmpty(white.rating) || scalarOrEmpty(headers.WhiteElo),\n        black: blackName,\n        black_rating: scalarOrEmpty(black.rating) || scalarOrEmpty(headers.BlackElo),\n        result,\n        winner_color: stringOrEmpty(g.colorOfWinner),\n        termination: stringOrEmpty(headers.Termination) || stringOrEmpty(g.resultMessage),\n        eco: stringOrEmpty(headers.ECO),\n        time_control: stringOrEmpty(headers.TimeControl) || (typeof g.daysPerTurn === 'number' ? `${g.daysPerTurn}d/turn` : ''),\n        rated: g.isRated === true,\n        ply_count: g.plyCount ?? '',\n        url: `https://www.chess.com/game/${kind}/${id}`,","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/chess/game.js#L29-L65","documentation":"After extracting player names and the result from the payload/PGN headers, summarizeGame requires a non-empty whiteName, blackName, and result; this CommandExecutionError signals the callback payload lacked the stable fields needed to produce a reliable summary row.","triggerScenarios":"payload yields empty white/black names (no players.<slot>.username and no pgnHeaders.White/Black) or an empty headers.Result — e.g. games in progress, aborted games, or truncated callback responses.","commonSituations":"Requesting a live game that hasn't finished (Result header empty or '*'); bots/variant games missing username fields; Chess.com omitting PGN headers for certain game kinds; partially cached payloads.","solutions":["Verify the game has finished and check the URL/game id is correct.","Inspect pgnHeaders for White/Black/Result; if the game is in progress, wait and retry later.","Fall back to alternate fields (e.g. other payload keys) if the endpoint's schema changed.","Re-fetch to rule out a truncated/partial cached response."],"exampleFix":"// before\nconst row = summarizeGame({ kind, id, payload }); // throws if names/result missing\n// after\nif (!stringOrEmpty(headers.White) || !stringOrEmpty(headers.Black) || !stringOrEmpty(headers.Result)) {\n  // skip in-progress games instead of crashing\n  return null;\n}\nconst row = summarizeGame({ kind, id, payload });","handlingStrategy":"validation","validationCode":"const headers = payload?.game?.pgnHeaders || {};\nconst ok = Boolean((headers.White && headers.Black) && headers.Result);\nif (!ok) console.warn('Game summary fields missing — game may be in progress');","typeGuard":"const hasSummaryFields = (h) => typeof h?.White === 'string' && h.White.length > 0 && typeof h?.Black === 'string' && h.Black.length > 0 && typeof h?.Result === 'string' && h.Result.length > 0;","tryCatchPattern":"try {\n  const row = summarizeGame({ kind, id, payload });\n} catch (err) {\n  if (String(err.message).includes('missing stable game summary fields')) {\n    // treat as in-progress/unfinished game and skip or retry later\n  } else throw err;\n}","preventionTips":["Only summarize finished games (filter by state/endTime when available)","Provide fallback name sources (usernames and PGN headers) before calling","Handle Result '*' (in-progress) explicitly"],"tags":["api-response","data-missing","chess"],"backgroundTag":"missing-required-field","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}