jackwener/OpenCLI · error · CommandExecutionError
Chess.com game archive entry has malformed player objects
Error message
Chess.com game archive entry has malformed player objects
What it means
After validating the game URL, mapGameRow() requires both game.white and game.black to be plain objects so it can read usernames, ratings, and results for each side. This throw fires when either player field is missing (and thus coerced via || {}) in a way that fails the object check — i.e. it is a non-object truthy value such as a string, number, or array.
Source
Thrown at clis/chess/utils.js:129
const cleaned = (namePart ? namePart[1] : tail).replace(/-/g, ' ').trim();
return cleaned;
}
/**
* Map a Chess.com game record (from the monthly archive) to a flat row.
* The viewer perspective controls win/loss orientation.
*/
export function mapGameRow(game, viewerUsername) {
if (!isPlainObject(game)) {
throw new CommandExecutionError('Chess.com game archive entry is not an object');
}
if (typeof game.url !== 'string' || !/^https:\/\/www\.chess\.com\/game\/(?:live|daily)\/\d+(?:$|[/?#])/i.test(game.url)) {
throw new CommandExecutionError('Chess.com game archive entry is missing a stable game URL');
}
const white = game?.white || {};
const black = game?.black || {};
if (!isPlainObject(white) || !isPlainObject(black)) {
throw new CommandExecutionError('Chess.com game archive entry has malformed player objects');
}
if (typeof white.username !== 'string' || !white.username.trim() || typeof black.username !== 'string' || !black.username.trim()) {
throw new CommandExecutionError('Chess.com game archive entry is missing stable player identities');
}
const viewerLower = String(viewerUsername || '').toLowerCase();
const viewerIsWhite = String(white.username || '').toLowerCase() === viewerLower;
const viewerIsBlack = String(black.username || '').toLowerCase() === viewerLower;
if (!viewerIsWhite && !viewerIsBlack) {
throw new CommandExecutionError('Chess.com game archive entry does not include the requested player');
}
const me = viewerIsWhite ? white : black;
const opp = viewerIsWhite ? black : white;
const eco = game?.eco || '';
return {
date: formatDate(game?.end_time),
time_class: game?.time_class || '',
rated: game?.rated === true,
my_color: viewerIsWhite ? 'white' : 'black',View on GitHub (pinned to 49907e53dc)
Solutions
- Re-fetch the monthly archive — pub archive entries always carry white/black as objects
- Fix the intermediate transform that replaced player objects with scalars
- In fixtures use white: { username: 'a', rating: 1500, result: 'win' } shape
- Add a filter that drops entries failing the player-object shape before mapping
Example fix
// before
const game = { url, white: 'hikaru', black: { username: 'magnus' } };
// after
const game = { url, white: { username: 'hikaru', rating: 2800, result: 'win' }, black: { username: 'magnus', rating: 2850, result: 'loss' } }; Defensive patterns
Strategy: validation
Validate before calling
if (!isPlain(game?.white) || !isPlain(game?.black)) {
throw new Error('game.white and game.black must be player objects');
}
function isPlain(v) { return v !== null && typeof v === 'object' && !Array.isArray(v); } Type guard
function hasPlayerObjects(g) {
const plain = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
return plain(g?.white) && plain(g?.black);
} Try / catch
try {
row = mapGameRow(game, user);
} catch (err) {
if (String(err.message).includes('malformed player objects')) {
console.warn('Skipping entry: white/black are not player objects');
} else { throw err; }
} Prevention
- Keep white/black as full objects { username, rating, result }; never collapse to usernames
- Validate archive entries as they enter your cache/pipeline
- Mirror pub API shapes exactly in fixtures
- Re-fetch from the pub archive when a stored entry fails shape checks
When it happens
Trigger: Archive entry where game.white or game.black is a truthy non-object (e.g. white: "hikaru" or white: [1500]) instead of { username, rating, result }, encountered while mapping rows for a player.
Common situations: A pre-processing step collapsed player objects into usernames or ratings; hand-written fixtures using shorthand; Chess.com schema drift on archive entries; passing entries from a different endpoint (e.g. a game summary endpoint with different player representation).
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Chess.com game archive entry is not an object
- Chess.com game archive entry is missing stable player identi
- Chess.com stats payload for ${kind} is not an object
- Chess.com stats payload for ${kind}.last is not an object
- Chess.com stats payload for ${kind}.best is not an object
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/f73fd4f4b3e1a714.
Report an issue: GitHub.