jackwener/OpenCLI · error · CommandExecutionError

Chess.com archives payload contains an unexpected archive UR

Error message

Chess.com archives payload contains an unexpected archive URL

What it means

Each entry in the archives array must be a string starting with https://api.chess.com/pub/player/ before the command fetches it. If Chess.com returns an unexpected entry (non-string, relative URL, or a different host), the command throws CommandExecutionError to avoid fetching an unvalidated URL.

Source

Thrown at clis/chess/games.js:48

        { name: 'username', type: 'string', required: true, positional: true, help: 'Chess.com username' },
        { name: 'limit', type: 'int', default: 10, help: `Number of recent games (1-${MAX_LIMIT})` },
    ],
    columns: ['date', 'time_class', 'rated', 'my_color', 'my_rating', 'my_result', 'opponent', 'opponent_rating', 'accuracy_white', 'accuracy_black', 'eco', 'opening_name', 'url'],
    func: async (kwargs) => {
        const username = validateUsername(kwargs.username);
        const limit = parseLimit(kwargs.limit);
        const archivesList = await chessApi(`/player/${encodeURIComponent(username)}/games/archives`);
        if (!Array.isArray(archivesList.archives)) {
            throw new CommandExecutionError('Chess.com archives payload is missing archives array');
        }
        const archives = archivesList.archives.slice().reverse();
        if (archives.length === 0) {
            throw new EmptyResultError(`Chess.com has no game archives for ${username}`);
        }
        const rows = [];
        for (let i = 0; i < archives.length && i < MAX_ARCHIVE_FETCHES && rows.length < limit; i++) {
            if (typeof archives[i] !== 'string' || !archives[i].startsWith('https://api.chess.com/pub/player/')) {
                throw new CommandExecutionError('Chess.com archives payload contains an unexpected archive URL');
            }
            const monthly = await chessApi(archives[i]);
            if (!Array.isArray(monthly.games)) {
                throw new CommandExecutionError('Chess.com monthly archive payload is missing games array');
            }
            const games = monthly.games.slice().reverse();
            for (const g of games) {
                rows.push(mapGameRow(g, username));
                if (rows.length >= limit) break;
            }
        }
        if (rows.length === 0) {
            throw new EmptyResultError(`Chess.com has games archives for ${username} but no games in the most recent ${MAX_ARCHIVE_FETCHES} months`);
        }
        return rows.slice(0, limit);
    },
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Check the current shape of /player/{username}/games/archives with curl to see what URL format Chess.com now returns
  2. Update this library (or patch the prefix check) if Chess.com changed its URL scheme
  3. Ensure no proxy is rewriting response bodies

Example fix

// before
if (!archives[i].startsWith('https://api.chess.com/pub/player/')) throw ...;
// after: tolerate both absolute and relative forms
const u = archives[i];
const ok = typeof u === 'string' && (u.startsWith('https://api.chess.com/pub/player/') || /^\/pub\/player\//.test(u));
if (!ok) throw new CommandExecutionError('unexpected archive URL');
Defensive patterns

Strategy: type-guard

Type guard

function isKnownArchiveUrl(u) { return typeof u === 'string' && (u.startsWith('https://api.chess.com/pub/player/') || u.startsWith('/pub/player/')); }

Try / catch

try {
  await gamesCmd(username);
} catch (e) {
  if (/unexpected archive URL/.test(e.message)) {
    // Chess.com likely changed URL format; re-inspect /games/archives payload
  } else throw e;
}

Prevention

When it happens

Trigger: archives[i] is not a string, or is a string not beginning with the expected https://api.chess.com/pub/player/ prefix — e.g. Chess.com switches to relative paths or a new domain, or the payload contains null/numeric entries.

Common situations: Chess.com API schema/URL changes; third-party mirrors or mocks of the API returning different URL formats; man-in-the-middle or proxy rewriting URLs.

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/00fb303ae8a2c66d. Report an issue: GitHub.