jackwener/OpenCLI · error · ArgumentError
twitter likes username must be a valid Twitter/X handle
Error message
twitter likes username must be a valid Twitter/X handle
What it means
The username argument is passed through normalizeTwitterScreenName, which strips/validates Twitter/X handle syntax. If a non-empty raw username yields no valid normalized handle, the value is not a legal screen name and ArgumentError is thrown, with an example command as remediation text.
Source
Thrown at clis/twitter/likes.js:226
const useOutputFile = Boolean(fetchAll && outputFile);
const maxPages = resolveMaxPages(kwargs, fetchAll);
const topByEngagement = Number(kwargs['top-by-engagement'] || 0);
if (useOutputFile && topByEngagement > 0) {
throw new ArgumentError('--top-by-engagement cannot be combined with --output-file');
}
if (outputFile && !fetchAll) {
throw new ArgumentError('--output-file requires --all');
}
if (resumeFile && !fetchAll) {
throw new ArgumentError('--resume-file requires --all');
}
if (outputFile && !resumeFile) {
throw new ArgumentError('--output-file requires --resume-file so partial archives remain resumable');
}
const rawUsername = String(kwargs.username ?? '').trim();
let username = normalizeTwitterScreenName(rawUsername);
if (rawUsername && !username) {
throw new ArgumentError('twitter likes username must be a valid Twitter/X handle', 'Example: opencli twitter likes @jack --limit 20');
}
const cookies = await page.getCookies({ url: 'https://x.com' });
const ct0 = cookies.find((c) => c.name === 'ct0')?.value || null;
if (!ct0)
throw new AuthRequiredError('x.com', 'Not logged into x.com (no ct0 cookie)');
// If no username provided, detect the logged-in user.
// Bridge wraps primitive page.evaluate returns as { session, data:<value> };
// unwrap so the href string is usable downstream.
if (!username) {
// Force a navigation to the home surface so the AppTabBar sidebar
// is rendered; the framework pre-nav lands on bare x.com which
// does not always expose AppTabBar_Profile_Link.
await page.goto('https://x.com/home');
await page.wait({ selector: '[data-testid="primaryColumn"]' });
const href = unwrapBrowserResult(await page.evaluate(`() => {
const link = document.querySelector('a[data-testid="AppTabBar_Profile_Link"]');
return link ? link.getAttribute('href') : null;
}`));View on GitHub (pinned to 49907e53dc)
Solutions
- Pass just the handle: `opencli twitter likes @jack --limit 20` (the @ prefix and alphanumerics/underscore, max 15 chars).
- Strip surrounding quotes/URL parts — extract the screen name from any profile URL first.
- Quote the argument in your shell so spaces don't split it, and check `set -x` output if scripting.
Example fix
// before opencli twitter likes 'https://x.com/jack?foo=1' // after opencli twitter likes @jack --limit 20
Defensive patterns
Strategy: validation
Validate before calling
function isValidHandle(raw) {
const h = raw.replace(/^@/, '');
return /^[A-Za-z0-9_]{1,15}$/.test(h);
}
if (!isValidHandle(process.argv[3])) throw new Error('Pass a valid handle, e.g. @jack'); Type guard
function isTwitterScreenName(v) {
return typeof v === 'string' && /^@?[A-Za-z0-9_]{1,15}$/.test(v);
} Try / catch
try {
await cli({ username: raw });
} catch (err) {
if (err instanceof ArgumentError && /valid Twitter\/X handle/.test(err.message)) {
// extract handle from URL or fix quoting, then retry
}
} Prevention
- Strip URLs to the screen name before passing the positional argument.
- Quote the username in shell scripts to avoid word splitting.
- Validate handles client-side with /^[A-Za-z0-9_]{1,15}$/ (optional leading @).
When it happens
Trigger: Passing something like `opencli twitter likes 'jack dorsey'` or `opencli twitter likes 'https://x.com/jack'` or a handle with invalid characters (!, spaces, >15 chars) as the positional username.
Common situations: Pasting a full profile URL instead of the handle; including trailing punctuation from copy-paste; shell quoting split the handle so the flag got a wrong value; typos like 'ja ck'.
Related errors
- --resume-file requires --all
- twitter download requires either <username> or --tweet-url
- Use either <username> or --tweet-url, not both
- twitter download username must be a valid Twitter/X handle
- --top-by-engagement cannot be combined with --output-file
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/5f977be55a55f7e1.
Report an issue: GitHub.