jackwener/OpenCLI · error · ArgumentError

Invalid Twitter/X username: ${JSON.stringify(username)}

Error message

Invalid Twitter/X username: ${JSON.stringify(username)}

What it means

Each comma-separated username must match USERNAME_RE = /^[A-Za-z0-9_]{1,15}$/ — X handles are 1–15 chars of letters, digits, and underscores. If any part fails, parseCommaSeparatedUsernames throws ArgumentError quoting the offending value via JSON.stringify. The full batch is rejected rather than partially run.

Source

Thrown at clis/twitter/list-batch-utils.js:26

    const raw = String(rawValue || '').trim();
    if (!raw) {
        throw new ArgumentError('At least one username is required', example);
    }

    const values = raw
        .split(',')
        .map((part) => part.trim().replace(/^@/, ''))
        .filter(Boolean);

    if (values.length === 0) {
        throw new ArgumentError('At least one username is required', example);
    }

    const seen = new Set();
    const usernames = [];
    for (const username of values) {
        if (!USERNAME_RE.test(username)) {
            throw new ArgumentError(`Invalid Twitter/X username: ${JSON.stringify(username)}`, example);
        }
        const key = username.toLowerCase();
        if (seen.has(key)) continue;
        seen.add(key);
        usernames.push(username);
    }

    return usernames;
}

export function parseBatchIntervalSeconds(rawValue) {
    const value = rawValue === undefined || rawValue === null || rawValue === ''
        ? DEFAULT_INTERVAL_SECONDS
        : Number(rawValue);
    if (!Number.isInteger(value) || value < 0 || value > MAX_INTERVAL_SECONDS) {
        throw new ArgumentError(`Invalid interval: ${JSON.stringify(rawValue)}. Expected an integer from 0 to ${MAX_INTERVAL_SECONDS}.`);
    }
    return value;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Use bare handles only: letters/digits/underscore, max 15 chars — strip URLs and display names from your input.
  2. Remove spaces around entries (trailing punctuation counts as part of the name after trim).
  3. Verify each handle on x.com; rename >15-char entries to their current valid handle.
  4. Pre-validate with /^[A-Za-z0-9_]{1,15}$/ in your tooling before invoking the CLI.

Example fix

// before
opencli twitter list-batch-add 123456789 --usernames "https://x.com/alice,Bob Smith"
ArgumentError: Invalid Twitter/X username: "Bob Smith"
// after
opencli twitter list-batch-add 123456789 --usernames "alice,bob_smith"
Defensive patterns

Strategy: validation

Validate before calling

const USERNAME_RE = /^[A-Za-z0-9_]{1,15}$/;
const bad = raw.split(',').map((p) => p.trim().replace(/^@/, '')).filter((p) => p && !USERNAME_RE.test(p));
if (bad.length) throw new Error(`Invalid handles: ${bad.join(', ')} — use 1-15 chars of A-Za-z0-9_`);

Type guard

function isValidHandle(u) {
  return typeof u === 'string' && /^[A-Za-z0-9_]{1,15}$/.test(u);
}

Try / catch

try {
  await runBatch(argv);
} catch (e) {
  if (e instanceof ArgumentError && /Invalid Twitter\/X username/.test(e.message)) {
    console.error(`${e.message} — strip URLs/display names; handles are 1-15 chars of letters, digits, underscore.`);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a part containing invalid characters (spaces, hyphens, dots, non-ASCII), longer than 15 chars, or an accidental embedded value like "alice, bob smith" — 'bob smith' fails the regex.

Common situations: Including full profile URLs (https://x.com/alice) instead of handles; pasting display names instead of handles; trailing punctuation from prose ("alice."); handles longer than 15 chars (old 20-char legacy names or typos); non-Latin scripts.

Related errors


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