jackwener/OpenCLI · error · CommandExecutionError

Chess.com callback returned malformed PGN headers

Error message

Chess.com callback returned malformed PGN headers

What it means

summarizeGame expects payload.game.pgnHeaders, when present, to be a plain object of PGN header key/values; this CommandExecutionError fires when it exists but has an unexpected shape (e.g. a string or array), protecting downstream header reads (White/Black/Result/Date).

Source

Thrown at clis/chess/game.js:26

import { UA, formatDate, isPlainObject, parseGameUrl } from './utils.js';

const CALLBACK_BASE = 'https://www.chess.com/callback';

function stringOrEmpty(value) {
    return typeof value === 'string' ? value : '';
}

function scalarOrEmpty(value) {
    return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' ? value : '';
}

export function summarizeGame({ kind, id, payload }) {
    if (!isPlainObject(payload) || !isPlainObject(payload.game)) {
        throw new CommandExecutionError('Chess.com callback returned no game payload');
    }
    const g = payload.game;
    if (g.pgnHeaders !== undefined && !isPlainObject(g.pgnHeaders)) {
        throw new CommandExecutionError('Chess.com callback returned malformed PGN headers');
    }
    if (payload.players !== undefined && !isPlainObject(payload.players)) {
        throw new CommandExecutionError('Chess.com callback returned malformed player metadata');
    }
    const players = payload.players || {};
    const byColor = {};
    for (const slot of ['top', 'bottom']) {
        const p = players[slot];
        if (p !== undefined && !isPlainObject(p)) {
            throw new CommandExecutionError('Chess.com callback returned malformed player metadata');
        }
        if (p?.color) byColor[p.color] = p;
    }
    const white = byColor.white || {};
    const black = byColor.black || {};
    const headers = g.pgnHeaders || {};
    const whiteName = stringOrEmpty(white.username) || stringOrEmpty(headers.White);
    const blackName = stringOrEmpty(black.username) || stringOrEmpty(headers.Black);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Inspect the actual pgnHeaders value returned and adapt parsing (e.g. parse a raw PGN string into headers).
  2. Pin/upgrade the CLI to match the current Chess.com callback schema.
  3. In tests, use fixtures captured from the real endpoint so shapes match.
  4. Guard at the fetch layer: validate pgnHeaders is an object before summarizing.

Example fix

// before
// assumes pgnHeaders is always an object
const headers = g.pgnHeaders || {};
// after
if (g.pgnHeaders !== undefined && !isPlainObject(g.pgnHeaders)) {
  throw new CommandExecutionError('Chess.com callback returned malformed PGN headers');
}
const headers = g.pgnHeaders || {};
Defensive patterns

Strategy: type-guard

Validate before calling

if (payload?.game?.pgnHeaders !== undefined && !isPlainObject(payload.game.pgnHeaders)) {
  throw new Error('pgnHeaders is not an object; parse raw PGN instead');
}

Type guard

const isPlainObject = (v) => Object.prototype.toString.call(v) === '[object Object]';
const hasValidPgnHeaders = (g) => g.pgnHeaders === undefined || isPlainObject(g.pgnHeaders);

Try / catch

try {
  const row = summarizeGame({ kind, id, payload });
} catch (err) {
  if (String(err.message).includes('malformed PGN headers')) {
    // normalize: parse raw PGN string into headers, then retry
  } else throw err;
}

Prevention

When it happens

Trigger: Chess.com callback returns game.pgnHeaders as a non-object (string of raw PGN, null treated as present, array) while being defined — i.e. `pgnHeaders !== undefined && !isPlainObject(pgnHeaders)`.

Common situations: Endpoint schema change (e.g. pgnHeaders became a raw PGN string); caching layers returning older/newer shapes; manual mock data in tests not matching the real shape.

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