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
- Inspect the actual pgnHeaders value returned and adapt parsing (e.g. parse a raw PGN string into headers).
- Pin/upgrade the CLI to match the current Chess.com callback schema.
- In tests, use fixtures captured from the real endpoint so shapes match.
- 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
- Test against live endpoint fixtures so shape changes are caught early
- Normalize raw PGN strings to header objects before summarizing
- Check Chess.com API changelogs after CLI upgrades
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.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Chess.com callback returned no game payload
- Chess.com callback returned malformed player metadata
- Bilibili ${label} API returned a malformed payload
- Bilibili ${label} API returned malformed data
- Bilibili ${label} API did not return replies
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/a22865c5fcf66006.
Report an issue: GitHub.