jackwener/OpenCLI · error · CommandExecutionError
Chess.com stats payload for ${kind} is not an object
Error message
Chess.com stats payload for ${kind} is not an object What it means
summarizeStats() extracts a time-class sub-object (e.g. stats.chess_rapid) from a Chess.com player stats payload. If that sub-key exists and is truthy but is not a plain object (array, string, number), the library throws rather than silently producing empty columns. It indicates the stats payload does not match the documented Chess.com /pub/player/{user}/stats schema for that kind.
Source
Thrown at clis/chess/utils.js:73
if (!resp.ok) throw new CommandExecutionError(`Chess.com API returned HTTP ${resp.status} for ${url}`);
let payload;
try {
payload = await resp.json();
} catch (error) {
throw new CommandExecutionError(`Chess.com API returned malformed JSON for ${url}: ${error?.message || error}`);
}
if (!isPlainObject(payload)) {
throw new CommandExecutionError(`Chess.com API returned an unexpected payload shape for ${url}`);
}
return payload;
}
/** Pull rating + record fields out of a stats sub-object (`chess_rapid` etc). */
export function summarizeStats(stats, kind) {
const k = stats?.[kind];
if (!k) return null;
if (!isPlainObject(k)) {
throw new CommandExecutionError(`Chess.com stats payload for ${kind} is not an object`);
}
if (!isOptionalPlainObject(k.last)) {
throw new CommandExecutionError(`Chess.com stats payload for ${kind}.last is not an object`);
}
if (!isOptionalPlainObject(k.best)) {
throw new CommandExecutionError(`Chess.com stats payload for ${kind}.best is not an object`);
}
if (!isOptionalPlainObject(k.record)) {
throw new CommandExecutionError(`Chess.com stats payload for ${kind}.record is not an object`);
}
const record = isPlainObject(k.record) ? k.record : {};
return {
kind: kind.replace(/^chess_/, ''),
rating_current: k.last?.rating ?? '',
rating_best: k.best?.rating ?? '',
wins: record.win ?? '',
losses: record.loss ?? '',
draws: record.draw ?? '',View on GitHub (pinned to 49907e53dc)
Solutions
- Re-fetch the stats payload fresh from https://api.chess.com/pub/player/{username}/stats to rule out stale/corrupt cached data
- Log typeof stats[kind] and JSON.stringify(stats[kind]) to identify the actual shape
- Pass the correct object: the stats payload itself, not a nested or stringified value
- If Chess.com changed the schema, update summarizeStats mapping for that kind
Example fix
// before const row = summarizeStats(JSON.parse(fs.readFileSync(cacheFile, 'utf8')).chess_rapid, 'chess_rapid'); // after const payload = JSON.parse(fs.readFileSync(cacheFile, 'utf8')); const row = isPlainObject(payload) ? summarizeStats(payload, 'chess_rapid') : null;
Defensive patterns
Strategy: type-guard
Validate before calling
// Guard before calling summarizeStats
if (!stats || typeof stats !== 'object' || Array.isArray(stats)) {
throw new Error('stats payload must be a plain object');
}
const k = stats[kind];
if (k != null && (typeof k !== 'object' || Array.isArray(k))) {
throw new Error(`${kind} must be an object, got ${typeof k}`);
} Type guard
function isStatSection(v) {
return v === null || v === undefined ||
(typeof v === 'object' && !Array.isArray(v));
}
// usage: if (!isStatSection(stats?.[kind])) { ...skip or handle... } Try / catch
try {
const row = summarizeStats(stats, kind);
} catch (err) {
if (String(err.message).includes('is not an object')) {
console.warn(`Skipping ${kind}: malformed stats section`);
} else { throw err; }
} Prevention
- Feed summarizeStats only payloads fetched fresh from /pub/player/{user}/stats
- Never store stringified or flattened values under chess_* keys in caches
- Validate cached JSON shapes before reusing them
- Keep test fixtures aligned with the live pub API schema
When it happens
Trigger: stats[kind] is truthy but not an object — e.g. chess_rapid is a string, number, or array in the payload fetched from https://api.chess.com/pub/player/{username}/stats and passed through rows()/row().
Common situations: Chess.com schema drift for a specific time-class key; a hand-built or cached stats object passed to summarizeStats in tests; a wrapper that stores serialized/JSON-string values under the kind key; caller passing the wrong parent object (whole payload instead of payload stats).
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.
Related errors
- Chess.com stats payload for ${kind}.last is not an object
- Chess.com stats payload for ${kind}.best is not an object
- Chess.com stats payload for ${kind}.record is not an object
- Chess.com game archive entry is not an object
- Chess.com game archive entry has malformed player objects
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/c3197430d2ec3604.
Report an issue: GitHub.