jackwener/OpenCLI · error · ArgumentError

Invalid Chess.com username

Error message

Invalid Chess.com username "${value}" Usernames are 3-25 chars: a-z, 0-9, hyphen, underscore.

What it means

An ArgumentError raised when the supplied username fails the USERNAME_RE pattern ^[a-zA-Z0-9_-]{3,25}$ (3-25 chars: letters, digits, hyphen, underscore). Chess.com usernames are constrained to this shape, so the library validates locally and fails fast before hitting the network.

Solutions

  1. Use the actual Chess.com username (the lowercase handle in the profile URL), 3-25 chars of a-z/0-9/_/- only.
  2. Trim stray quotes, whitespace, or shell escapes from the argument.
  3. Pre-validate in the caller with the same regex before invoking the library.

Example fix

// before
await chessStats({ username: 'Hikaru Nakamura' }); // space -> throws
// after
await chessStats({ username: 'hikaru' });
Defensive patterns

Strategy: validation

Validate before calling

const USERNAME_RE = /^[a-zA-Z0-9_-]{3,25}$/;
function isValidUsername(v) {
  return typeof v === 'string' && USERNAME_RE.test(v.trim());
}

Type guard

function isValidUsername(v) {
  return typeof v === 'string' && /^[a-zA-Z0-9_-]{3,25}$/.test(v.trim());
}

Try / catch

if (!isValidUsername(username)) {
  throw new Error('Username must be 3-25 chars: a-z, 0-9, hyphen, underscore.');
}
try {
  const rows = await chessStats({ username });
} catch (e) {
  if (e.name === 'ArgumentError') console.error(e.message, e.hint || '');
  else throw e;
}

Prevention

When it happens

Trigger: Passing a username shorter than 3 chars, longer than 25 chars, or containing spaces, '@', dots, non-ASCII, or URL characters to any command that routes through validateUsername.

Common situations: Pasting a display name with spaces instead of the URL-style username; passing an email address; accidentally including quotes or shell-escaping artifacts; passing a full profile URL as the username.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/3e37a762130efbba. Report an issue: GitHub.

Appendix: source

Thrown at clis/chess/utils.js:25

export const API_BASE = 'https://api.chess.com/pub';
export const UA = 'Mozilla/5.0 (compatible; opencli/1.0)';

const USERNAME_RE = /^[a-zA-Z0-9_-]{3,25}$/;
const GAME_URL_RE = /^https:\/\/www\.chess\.com\/game\/(live|daily)\/(\d+)/i;

export function isPlainObject(value) {
    return value !== null && typeof value === 'object' && !Array.isArray(value);
}

function isOptionalPlainObject(value) {
    return value === undefined || value === null || isPlainObject(value);
}

export function validateUsername(value) {
    const s = String(value ?? '').trim().toLowerCase();
    if (!s) throw new ArgumentError('<username> is required');
    if (!USERNAME_RE.test(s)) {
        throw new ArgumentError(`Invalid Chess.com username "${value}"`, 'Usernames are 3-25 chars: a-z, 0-9, hyphen, underscore.');
    }
    return s;
}

export function parseGameUrl(value) {
    const s = String(value ?? '').trim();
    if (!s) throw new ArgumentError('<game-url> is required');
    const m = s.match(GAME_URL_RE);
    if (!m) {
        throw new ArgumentError(
            `Invalid Chess.com game URL: "${value}"`,
            'Expected https://www.chess.com/game/live/<id> or https://www.chess.com/game/daily/<id>.',
        );
    }
    return { kind: m[1].toLowerCase(), id: m[2] };
}

export async function chessApi(path, fetchImpl = fetch) {

View on GitHub (pinned to 49907e53dc)