{"record":{"id":"dcab468a02a5805a","repo":"jackwener/OpenCLI","slug":"chess-com-callback-returned-malformed-player-metad","errorCode":null,"errorMessage":"Chess.com callback returned malformed player metadata","messagePattern":"Chess\\.com callback returned malformed player metadata","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/chess/game.js","lineNumber":29,"sourceCode":"\nfunction stringOrEmpty(value) {\n    return typeof value === 'string' ? value : '';\n}\n\nfunction scalarOrEmpty(value) {\n    return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' ? value : '';\n}\n\nexport function summarizeGame({ kind, id, payload }) {\n    if (!isPlainObject(payload) || !isPlainObject(payload.game)) {\n        throw new CommandExecutionError('Chess.com callback returned no game payload');\n    }\n    const g = payload.game;\n    if (g.pgnHeaders !== undefined && !isPlainObject(g.pgnHeaders)) {\n        throw new CommandExecutionError('Chess.com callback returned malformed PGN headers');\n    }\n    if (payload.players !== undefined && !isPlainObject(payload.players)) {\n        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');","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/chess/game.js#L11-L47","documentation":"This duplicate message guards two separate checks in summarizeGame; this instance (line 29) fires when payload.players is defined but not a plain object. The CLI requires well-formed player metadata keyed by 'top'/'bottom' to build the game summary row.","triggerScenarios":"Chess.com callback response contains a `players` field whose value is not a plain object (array, string, null-as-present) — caught by `payload.players !== undefined && !isPlainObject(payload.players)`.","commonSituations":"API schema drift where players became a list; HTML/error bodies partially parsed; stale cached responses from an older endpoint version.","solutions":["Inspect the raw payload's players field to see its actual shape and update parsing.","Retry the fetch in case a transient bad response caused the malformed shape.","Check for Chess.com API changes and update the CLI or pin a compatible version.","Validate response shape at the fetch boundary before calling summarizeGame."],"exampleFix":"// before\nconst players = payload.players || {}; // crashes later if not an object\n// after\nif (payload.players !== undefined && !isPlainObject(payload.players)) {\n  throw new CommandExecutionError('Chess.com callback returned malformed player metadata');\n}\nconst players = payload.players || {};","handlingStrategy":"type-guard","validationCode":"if (payload?.players !== undefined && !isPlainObject(payload.players)) {\n  throw new Error('players is not a plain object');\n}","typeGuard":"const isPlainObject = (v) => Object.prototype.toString.call(v) === '[object Object]';\nconst hasValidPlayers = (p) => p.players === undefined || isPlainObject(p.players);","tryCatchPattern":"try {\n  const row = summarizeGame({ kind, id, payload });\n} catch (err) {\n  if (String(err.message).includes('malformed player metadata')) {\n    console.error('players field shape changed; inspect raw payload');\n  } else throw err;\n}","preventionTips":["Validate payload.players shape at the fetch boundary","Keep fixtures from the real endpoint in tests","Handle variant game types that may alter the players field"],"tags":["api-response","schema-validation","chess"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}