{"record":{"id":"481a2884e589a62e","repo":"jackwener/OpenCLI","slug":"chess-com-api-returned-an-invalid-response-object","errorCode":null,"errorMessage":"Chess.com API returned an invalid response object for ${url}","messagePattern":"Chess\\.com API returned an invalid response object for (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/chess/utils.js","lineNumber":52,"sourceCode":"    if (!m) {\n        throw new ArgumentError(\n            `Invalid Chess.com game URL: \"${value}\"`,\n            'Expected https://www.chess.com/game/live/<id> or https://www.chess.com/game/daily/<id>.',\n        );\n    }\n    return { kind: m[1].toLowerCase(), id: m[2] };\n}\n\nexport async function chessApi(path, fetchImpl = fetch) {\n    const url = path.startsWith('http') ? path : `${API_BASE}${path}`;\n    let resp;\n    try {\n        resp = await fetchImpl(url, { headers: { 'User-Agent': UA, accept: 'application/json' } });\n    } catch (error) {\n        throw new CommandExecutionError(`Failed to fetch Chess.com API ${url}: ${error?.message || error}`);\n    }\n    if (!resp || typeof resp !== 'object') {\n        throw new CommandExecutionError(`Chess.com API returned an invalid response object for ${url}`);\n    }\n    if (resp.status === 404) throw new EmptyResultError(`Chess.com returned 404 for ${url}`);\n    if (!resp.ok) throw new CommandExecutionError(`Chess.com API returned HTTP ${resp.status} for ${url}`);\n    let payload;\n    try {\n        payload = await resp.json();\n    } catch (error) {\n        throw new CommandExecutionError(`Chess.com API returned malformed JSON for ${url}: ${error?.message || error}`);\n    }\n    if (!isPlainObject(payload)) {\n        throw new CommandExecutionError(`Chess.com API returned an unexpected payload shape for ${url}`);\n    }\n    return payload;\n}\n\n/** Pull rating + record fields out of a stats sub-object (`chess_rapid` etc). */\nexport function summarizeStats(stats, kind) {\n    const k = stats?.[kind];","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/chess/utils.js#L34-L70","documentation":"A CommandExecutionError thrown when the fetch resolves but the result is not a usable Response-like object (null, undefined, or a non-object). The library expects resp.status/resp.ok/resp.json() to exist, so it fails fast with the offending URL in the message.","triggerScenarios":"A custom fetchImpl passed to chessApi that returns null/undefined or a plain value (e.g. returning parsed JSON instead of a Response), or a mocked fetch in tests with an incomplete stub.","commonSituations":"Test doubles like fetch: async () => ({ json: ... }) missing from the contract, or wrappers that unwrap the Response before returning it.","solutions":["Ensure the default global fetch is used, or make your fetchImpl return a real Response (or Response-like object with status, ok, and json()).","Fix test stubs to mirror the Response shape: { ok: true, status: 200, json: async () => ({...}) }.","Avoid wrappers that return await resp.json() instead of the Response itself."],"exampleFix":"// before\nchessApi(path, async () => ({ chess_rapid: {} })); // not a Response\n// after\nchessApi(path, async () => new Response(JSON.stringify({ chess_rapid: {} }), { status: 200 }));","handlingStrategy":"type-guard","validationCode":"// Validate any custom fetchImpl before use:\nfunction isValidFetchImpl(fn) {\n  return typeof fn === 'function';\n}","typeGuard":"function isResponseLike(resp) {\n  return resp != null && typeof resp === 'object'\n    && typeof resp.status === 'number'\n    && typeof resp.ok === 'boolean'\n    && typeof resp.json === 'function';\n}","tryCatchPattern":"try {\n  const payload = await chessApi(path, myFetch);\n} catch (e) {\n  if (/invalid response object/.test(e.message)) {\n    console.error('fetchImpl must return a Response-like object');\n  } else throw e;\n}","preventionTips":["Never wrap chessApi with functions that unwrap the Response before returning it.","Make test stubs implement status, ok, and json().","Prefer returning new Response(...) in mocks."],"tags":["fetch","contract-violation","mocking","chess-com"],"backgroundTag":"invalid-response-object","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}