{"record":{"id":"a8e426638ed9db88","repo":"jackwener/OpenCLI","slug":"chess-com-stats-payload-for-kind-record-is-not","errorCode":null,"errorMessage":"Chess.com stats payload for ${kind}.record is not an object","messagePattern":"Chess\\.com stats payload for (.+?)\\.record is not an object","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/chess/utils.js","lineNumber":82,"sourceCode":"    }\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)) {\n        throw new CommandExecutionError(`Chess.com stats payload for ${kind} is not an object`);\n    }\n    if (!isOptionalPlainObject(k.last)) {\n        throw new CommandExecutionError(`Chess.com stats payload for ${kind}.last is not an object`);\n    }\n    if (!isOptionalPlainObject(k.best)) {\n        throw new CommandExecutionError(`Chess.com stats payload for ${kind}.best is not an object`);\n    }\n    if (!isOptionalPlainObject(k.record)) {\n        throw new CommandExecutionError(`Chess.com stats payload for ${kind}.record is not an object`);\n    }\n    const record = isPlainObject(k.record) ? k.record : {};\n    return {\n        kind: kind.replace(/^chess_/, ''),\n        rating_current: k.last?.rating ?? '',\n        rating_best: k.best?.rating ?? '',\n        wins: record.win ?? '',\n        losses: record.loss ?? '',\n        draws: record.draw ?? '',\n    };\n}\n\n/** Parse an end_time epoch (seconds) into YYYY-MM-DD. */\nexport function formatDate(epochSeconds) {\n    if (!epochSeconds || typeof epochSeconds !== 'number') return '';\n    return new Date(epochSeconds * 1000).toISOString().slice(0, 10);\n}\n","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/chess/utils.js#L64-L100","documentation":"summarizeStats() validates that k.record (win/loss/draw counts) is either absent/null or a plain object. This throw fires when k.record exists but is not a plain object. Unlike last/best, record defaults to {} when missing, but a wrong-typed present value is rejected so wins/losses/draws extraction is well-defined.","triggerScenarios":"stats[kind].record is a truthy non-object — e.g. record: \"10/5/2\" or record: [10,5,2] — in the payload flowing through rows() or row().","commonSituations":"Aggregation code stringified the W/L/D record; a cached payload from a differently-shaped source; test fixtures built with compact record notation; upstream schema change on the Chess.com stats endpoint.","solutions":["Re-fetch the stats from the pub API; record must be an object like { win: 10, loss: 5, draw: 2 }","Fix whatever serialized the record into a string/array before calling summarizeStats","Use record: { win: 0, loss: 0, draw: 0 } in fixtures instead of compact strings","Update the mapping if Chess.com reshaped the record field"],"exampleFix":"// before\nstats.chess_rapid.record = '10-5-2';\n// after\nstats.chess_rapid.record = { win: 10, loss: 5, draw: 2 };","handlingStrategy":"validation","validationCode":"const record = stats?.[kind]?.record;\nif (record != null && (typeof record !== 'object' || Array.isArray(record))) {\n  throw new Error(`${kind}.record must be an object like { win, loss, draw }`);\n}","typeGuard":"function hasValidRecord(k) {\n  return k?.record == null ||\n    (typeof k.record === 'object' && !Array.isArray(k.record) &&\n      ['win', 'loss', 'draw'].every((key) => key in k.record));\n}","tryCatchPattern":"try {\n  const row = summarizeStats(stats, 'chess_rapid');\n} catch (err) {\n  if (String(err.message).includes('.record is not an object')) {\n    console.warn('record malformed; W/L/D columns will be skipped');\n  } else { throw err; }\n}","preventionTips":["Represent records as { win, loss, draw } objects, not '10-5-2' strings or arrays","Validate record shape before persisting aggregates","Refetch the pub stats endpoint when a stored record fails validation","Keep normalization code from collapsing nested objects into compact strings"],"tags":["api","schema-validation","chess-com","stats"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}