{"record":{"id":"9808a2c7070d457e","repo":"jackwener/OpenCLI","slug":"invalid-chess-com-game-url-value-expected-ht","errorCode":null,"errorMessage":"Invalid Chess.com game URL: \"${value}\" Expected https://www.chess.com/game/live/<id> or https://www.chess.com/game/daily/<id>.","messagePattern":"Invalid Chess\\.com game URL: \"(.+?)\" Expected https://www\\.chess\\.com/game/live/<id> or https://www\\.chess\\.com/game/daily/<id>\\.","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/chess/utils.js","lineNumber":35,"sourceCode":"function isOptionalPlainObject(value) {\n    return value === undefined || value === null || isPlainObject(value);\n}\n\nexport function validateUsername(value) {\n    const s = String(value ?? '').trim().toLowerCase();\n    if (!s) throw new ArgumentError('<username> is required');\n    if (!USERNAME_RE.test(s)) {\n        throw new ArgumentError(`Invalid Chess.com username \"${value}\"`, 'Usernames are 3-25 chars: a-z, 0-9, hyphen, underscore.');\n    }\n    return s;\n}\n\nexport function parseGameUrl(value) {\n    const s = String(value ?? '').trim();\n    if (!s) throw new ArgumentError('<game-url> is required');\n    const m = s.match(GAME_URL_RE);\n    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    }","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/chess/utils.js#L17-L53","documentation":"An ArgumentError thrown by parseGameUrl when the provided string does not match GAME_URL_RE: ^https:\\/\\/www\\.chess\\.com\\/game\\/(live|daily)\\/(\\d+). The regex captures the game kind (live or daily) and the numeric game id; anything else is rejected before an API call is made.","triggerScenarios":"Passing a chess.com/games/ URL, a mobile share link, an empty-id URL like /game/live/, an http:// (non-https) URL, a URL without the numeric id, or a Study/Puzzle URL.","commonSituations":"Copying the URL from the games archive list page (different path); using a shortened or localized-domain link; pasting a URL that includes trailing text the regex cannot anchor; Chess.com introducing new game types (e.g. /game/live/ vs newer variants) not covered by the regex.","solutions":["Copy the URL directly from an individual game page: https://www.chess.com/game/live/<id> or https://www.chess.com/game/daily/<id>.","Strip any trailing garbage (quotes, query fragments copied along with the link).","If you have a games-list or archive URL, open the game first and copy its canonical URL.","If Chess.com added new game-path variants, extend GAME_URL_RE in clis/chess/utils.js:11."],"exampleFix":"// before\nparseGameUrl('https://www.chess.com/games/view/12345'); // throws\n// after\nparseGameUrl('https://www.chess.com/game/live/12345');","handlingStrategy":"validation","validationCode":"const GAME_URL_RE = /^https:\\/\\/www\\.chess\\.com\\/game\\/(live|daily)\\/(\\d+)/i;\nfunction isValidGameUrl(v) {\n  return typeof v === 'string' && GAME_URL_RE.test(v.trim());\n}","typeGuard":"function parseGameUrlSafe(v) {\n  const m = typeof v === 'string' ? v.trim().match(/^https:\\/\\/www\\.chess\\.com\\/game\\/(live|daily)\\/(\\d+)/i) : null;\n  return m ? { kind: m[1].toLowerCase(), id: m[2] } : null;\n}","tryCatchPattern":"try {\n  const { kind, id } = parseGameUrl(gameUrl);\n} catch (e) {\n  if (e.name === 'ArgumentError') {\n    console.error('Expected https://www.chess.com/game/live/<id> or .../game/daily/<id>');\n  } else throw e;\n}","preventionTips":["Copy the URL from the individual game page, not the games list.","Pre-validate URLs with the same regex before calling.","Strip trailing text/quotes when pasting from chat or docs."],"tags":["argument-error","validation","url-parsing","regex"],"backgroundTag":"invalid-url-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}