jackwener/OpenCLI · error · CommandExecutionError

Chess.com game archive entry is not an object

Error message

Chess.com game archive entry is not an object

What it means

mapGameRow() maps one entry from a Chess.com monthly games archive into a flat row. The first guard requires each game entry to be a plain object; if an entry in the games array is null, an array, or a scalar, this error is thrown. It protects the rest of the mapper from dereferencing malformed entries.

Source

Thrown at clis/chess/utils.js:121

 * (`https://www.chess.com/openings/Reti-Opening-Nimzo-Larsen-Variation-2...g6-...`).
 * Returns '' for short-code eco values (`A01`) where no name is encoded.
 */
export function openingName(eco) {
    if (typeof eco !== 'string' || !eco.startsWith('http')) return '';
    const tail = eco.replace(/\/+$/, '').split('/').pop() || '';
    if (!tail) return '';
    const namePart = tail.match(/^([^.]+?)(?:-\d|\.\.\.|$)/);
    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');
    }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Ensure each element passed to mapGameRow is a single game object — map over data.games and filter with isPlainObject first
  2. Parse JSON entries before mapping if your data source returns strings
  3. Filter null/malformed entries from the archive array before mapping
  4. Re-fetch the archive if Chess.com returned an unexpected structure

Example fix

// before
const rows = archive.games.map((g) => mapGameRow(g, user));
// after
const rows = archive.games.filter(isPlainObject).map((g) => mapGameRow(g, user));
Defensive patterns

Strategy: type-guard

Validate before calling

const games = archive?.games ?? [];
for (const g of games) {
  if (g === null || typeof g !== 'object' || Array.isArray(g)) {
    throw new Error('archive contains a non-object game entry');
  }
}

Type guard

function isGameEntry(v) {
  return v !== null && typeof v === 'object' && !Array.isArray(v) &&
    typeof v.url === 'string' && v.url.startsWith('https://www.chess.com/game/');
}

Try / catch

try {
  rows = games.map((g) => mapGameRow(g, user));
} catch (err) {
  if (String(err.message).includes('archive entry is not an object')) {
    rows = games.filter(isGameEntry).map((g) => mapGameRow(g, user));
  } else { throw err; }
}

Prevention

When it happens

Trigger: An element of the games array returned by /pub/player/{user}/games/{yyyy}/{mm} (iterated by row()) is not a plain object — e.g. null entries, or the caller passed the whole archive object/array instead of a single game entry.

Common situations: Caller accidentally passes the entire {games:[...]} wrapper or the archive array instead of one element; Chess.com includes null entries in an archive; a custom fetch/mock returns entries as JSON strings that were never parsed.

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


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/c7e712cb5b929ed0. Report an issue: GitHub.