{"record":{"id":"e4c2570fcca0b90d","repo":"jackwener/OpenCLI","slug":"player-must-be-like-3741-niko-a-player-url-or-a","errorCode":null,"errorMessage":"player must be like 3741/niko, a player URL, or a stats player URL","messagePattern":"player must be like 3741/niko, a player URL, or a stats player URL","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/hltv/utils.js","lineNumber":189,"sourceCode":"  }\n\n  return { teamId: match[1], slug: match[2].toLowerCase() };\n}\n\nexport function parsePlayerRef(value, defaultValue = '3741/niko') {\n  const raw = String(value ?? defaultValue).trim();\n  if (!raw) throw new ArgumentError('player is required');\n\n  let path = raw;\n  if (/^https?:\\/\\//i.test(raw)) path = parseHltvUserUrl(raw, 'player').pathname;\n  path = path.replace(/^https?:\\/\\/[^/]+/i, '').replace(/^\\/+/, '');\n\n  const statsMatch = path.match(/^stats\\/players(?:\\/matches)?\\/(\\d+)\\/([a-z0-9-]+)/i);\n  const playerMatch = path.match(/^player\\/(\\d+)\\/([a-z0-9-]+)/i);\n  const compactMatch = path.match(/^(\\d+)\\/([a-z0-9-]+)$/i);\n  const match = statsMatch || playerMatch || compactMatch;\n  if (!match) {\n    throw new ArgumentError('player must be like 3741/niko, a player URL, or a stats player URL');\n  }\n\n  return { playerId: match[1], slug: match[2].toLowerCase() };\n}\n\nfunction formatDate(date) {\n  const yyyy = date.getUTCFullYear();\n  const mm = String(date.getUTCMonth() + 1).padStart(2, '0');\n  const dd = String(date.getUTCDate()).padStart(2, '0');\n  return `${yyyy}-${mm}-${dd}`;\n}\n\nfunction addMonths(date, months) {\n  const copy = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n  copy.setUTCMonth(copy.getUTCMonth() + months);\n  return copy;\n}\n","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/hltv/utils.js#L171-L207","documentation":"This ArgumentError is thrown by parsePlayerRef when the player string is non-empty but matches none of the accepted formats: compact 'id/slug', '/player/id/slug', or '/stats/players(/matches)/id/slug' paths (URLs are reduced to their pathname first). It means the library could not extract a numeric playerId and slug from the input. HLTV players are identified by the id/slug pair, so an unparseable ref cannot be turned into a stats URL.","triggerScenarios":"playerA('niko'), playerB('3741'), { player: 'hltv.org/player' }, a URL whose pathname lacks the id/slug pair (e.g. /stats/players or a team URL), or slug containing characters outside [a-z0-9-].","commonSituations":"Passing only a nickname ('niko') or only an id; pasting a profile URL with a trailing fragment that breaks parsing; mixing up team and player refs; older code paths passing 'players/3741/niko' (plural) which no pattern matches.","solutions":["Pass the full ref in a supported form: '3741/niko', 'player/3741/niko', 'stats/players/3741/niko', or a full URL like https://www.hltv.org/player/3741/niko.","Look up the numeric player id on HLTV and append the URL slug; a nickname alone is not an accepted format.","Verify the URL is a player page (path starts with /player/<digits>/ or /stats/players/...), not a team or match page.","Strip query strings/fragments and trailing slashes if constructing the ref manually."],"exampleFix":"// before\nbuildPlayerUrl('niko'); // ArgumentError\n// after\nbuildPlayerUrl('3741/niko');\n// or\nbuildPlayerUrl('https://www.hltv.org/player/3741/niko');","handlingStrategy":"validation","validationCode":"const PLAYER_REF_RE = /^(?:https?:\\/\\/[^/]+)?\\/?\\s*(?:stats\\/players(?:\\/matches)?|player)?\\/(\\d+)\\/([a-z0-9-]+)/i;\nfunction isParsablePlayerRef(v) {\n  const s = String(v ?? '').replace(/^https?:\\/\\/[^/]+/i, '').replace(/^\\/+/, '');\n  return /^(stats\\/players(?:\\/matches)?\\/\\d+\\/[a-z0-9-]+|player\\/\\d+\\/[a-z0-9-]+|\\d+\\/[a-z0-9-]+)$/i.test(s);\n}\nif (!isParsablePlayerRef(input)) throw new TypeError('player ref must be id/slug or a player/stats-player URL');","typeGuard":"function isPlayerRef(v) {\n  return typeof v === 'string' && /^(?:stats\\/players(?:\\/matches)?\\/\\d+|player\\/\\d+|\\d+)\\/[a-z0-9-]+/i.test(v.replace(/^https?:\\/\\/[^/]+/i, '').replace(/^\\/+/, ''));\n}","tryCatchPattern":"try {\n  return buildPlayerUrl(input);\n} catch (err) {\n  if (err.name === 'ArgumentError' && err.message.startsWith('player must be like')) {\n    throw new Error(`Unsupported player ref \"${input}\" — use id/slug or a HLTV player URL`, { cause: err });\n  }\n  throw err;\n}","preventionTips":["Always carry both the numeric id and the slug; a nickname alone is never enough.","Normalize URLs to pathname + strip query/fragment before validating shape.","Keep player and team refs in separate fields so formats don't get crossed.","Unit-test refs with the same regex family used by the library (stats/player/compact patterns)."],"tags":["argument-error","validation","url-parsing","hltv"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}