{"record":{"id":"ac5f9a6cecb09287","repo":"jackwener/OpenCLI","slug":"lichess-username-value-is-not-a-valid-handle","errorCode":null,"errorMessage":"lichess username \"${value}\" is not a valid handle. Allowed: letters, digits, underscore, dash; length 2-30.","messagePattern":"lichess username \"(.+?)\" is not a valid handle\\. Allowed: letters, digits, underscore, dash; length 2-30\\.","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/lichess/utils.js","lineNumber":26,"sourceCode":"export const LICHESS_BASE = 'https://lichess.org';\nconst UA = 'opencli-lichess-adapter/1.0 (+https://github.com/jackwener/opencli; mailto:opencli@example.com)';\n\n// Lichess usernames are 2-30 chars: letters, digits, underscore, dash. Case-insensitive.\nconst USERNAME_PATTERN = /^[A-Za-z0-9_-]{2,30}$/;\n\n// `perfType` values lichess accepts for the `/api/player/top/<n>/<perf>` endpoint.\n// Source: lichess-org/api docs.\nexport const LICHESS_PERFS = new Set([\n    'ultraBullet', 'bullet', 'blitz', 'rapid', 'classical',\n    'chess960', 'crazyhouse', 'antichess', 'atomic', 'horde',\n    'kingOfTheHill', 'racingKings', 'threeCheck',\n]);\n\nexport function requireUsername(value) {\n    const raw = String(value ?? '').trim();\n    if (!raw) throw new ArgumentError('lichess username is required');\n    if (!USERNAME_PATTERN.test(raw)) {\n        throw new ArgumentError(\n            `lichess username \"${value}\" is not a valid handle`,\n            'Allowed: letters, digits, underscore, dash; length 2-30.',\n        );\n    }\n    return raw;\n}\n\nexport function requirePerf(value) {\n    const raw = String(value ?? '').trim();\n    if (!raw) throw new ArgumentError('lichess perf is required (e.g. \"blitz\", \"bullet\", \"rapid\")');\n    if (!LICHESS_PERFS.has(raw)) {\n        throw new ArgumentError(\n            `lichess perf \"${value}\" is not recognised`,\n            `Allowed values: ${[...LICHESS_PERFS].join(', ')}.`,\n        );\n    }\n    return raw;\n}","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/lichess/utils.js#L8-L44","documentation":"This ArgumentError is thrown by `requireUsername` when the supplied username fails `USERNAME_PATTERN`: only letters, digits, underscore, and dash are allowed, with a length of 2-30. It prevents sending malformed handles to the Lichess API.","triggerScenarios":"Calling `username()` (via `requireUsername`) with a value containing spaces, `@`, dots, slashes, or other special characters, or a handle shorter than 2 or longer than 30 characters.","commonSituations":"Passing a full profile URL or `@mention` instead of the bare handle; including a trailing newline from copy-paste (trimmed, but embedded whitespace fails); test placeholders like 'x'; non-Latin-script usernames being normalized elsewhere.","solutions":["Strip protocol/URL parts and leading '@' so only the bare handle is passed","Validate the handle against /^[A-Za-z0-9_-]{2,30}$/ before calling","Remove illegal characters or correct the typo","Note Lichess handles are ASCII-only — transliterate if needed"],"exampleFix":"// before\nawait username('@DrNykterstein'); // invalid: '@' not allowed\n// after\nconst handle = raw.replace(/^@/, '').trim();\nif (!/^[A-Za-z0-9_-]{2,30}$/.test(handle)) throw new Error('bad handle');\nawait username(handle);","handlingStrategy":"validation","validationCode":"const USERNAME_RE = /^[A-Za-z0-9_-]{2,30}$/;\nfunction sanitizeHandle(raw) {\n  const s = String(raw ?? '').trim().replace(/^@/, '');\n  if (!USERNAME_RE.test(s)) throw new TypeError(`invalid lichess handle: ${raw}`);\n  return s;\n}\nawait username(sanitizeHandle(input));","typeGuard":"function isValidHandle(v) {\n  return typeof v === 'string' && /^[A-Za-z0-9_-]{2,30}$/.test(v);\n}","tryCatchPattern":"try {\n  await username(raw);\n} catch (e) {\n  if (e instanceof ArgumentError && /not a valid handle/.test(e.message)) {\n    console.error('Handles are 2-30 chars: letters, digits, _ or - (no @, spaces, or dots).');\n    process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Strip URL prefixes and leading '@' before passing a handle","Validate against /^[A-Za-z0-9_-]{2,30}$/ client-side first","Copy handles directly from lichess.org profile, not from formatted text","Remember Lichess handles are ASCII-only"],"tags":["lichess","argument-validation","invalid-format","regex"],"backgroundTag":"input-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}