jackwener/OpenCLI · error · ArgumentError
twitter followers user must be a valid Twitter/X handle
Error message
twitter followers user must be a valid Twitter/X handle
What it means
The library normalizes the user argument with normalizeTwitterScreenName; if a non-empty user string was given but normalization produced nothing, the value is not a valid Twitter/X handle. This guards against typos, embedded URLs, or values with illegal characters being sent to the API. It throws immediately as an ArgumentError with an example in the hint.
Source
Thrown at clis/twitter/followers.js:102
required: false,
help: 'Twitter/X handle (with or without @). Omit to fetch followers of the currently logged-in account.',
},
{ name: 'limit', type: 'int', default: 50, help: 'Maximum number of follower rows to return (default 50). Must be a positive integer.' },
],
// Preserve the historical three-column contract even though the GraphQL
// payload also contains per-user relationship counts. Use `twitter profile`
// when a dedicated follower count is needed.
columns: ['screen_name', 'name', 'bio'],
func: async (page, kwargs) => {
const limit = kwargs.limit;
if (!Number.isInteger(limit) || limit <= 0) {
throw new ArgumentError('limit must be a positive integer');
}
const rawUser = String(kwargs.user ?? '').trim();
let targetUser = normalizeScreenName(rawUser);
if (rawUser && !targetUser) {
throw new ArgumentError('twitter followers user must be a valid Twitter/X handle', 'Example: opencli twitter followers @elonmusk --limit 100');
}
await page.goto('https://x.com/home');
await page.wait({ selector: '[data-testid="primaryColumn"]' });
const cookies = await page.getCookies({ url: 'https://x.com' });
const ct0 = cookies.find((cookie) => cookie.name === 'ct0')?.value || null;
if (!ct0) {
throw new AuthRequiredError('x.com', 'Not logged into x.com (no ct0 cookie)');
}
if (!targetUser) {
// Bridge wraps primitive page.evaluate returns as { session, data:<value> };
// unwrap so the href string is usable downstream.
const href = unwrapBrowserResult(await page.evaluate(`() => {
const link = document.querySelector('a[data-testid="AppTabBar_Profile_Link"]');
return link ? link.getAttribute('href') : null;
}`));
if (!href || typeof href !== 'string') {
throw new AuthRequiredError('x.com', 'Could not find logged-in user profile link. Are you logged in?');View on GitHub (pinned to 49907e53dc)
Solutions
- Pass only the handle, with or without a single leading @, e.g. @elonmusk or elonmusk
- Strip URL parts first: const handle = url.split('/').pop().split('?')[0]
- Validate with /^@?[A-Za-z0-9_]{1,15}$/ before calling
Example fix
// before opencli twitter followers "https://x.com/elonmusk" // after opencli twitter followers @elonmusk --limit 100
Defensive patterns
Strategy: validation
Validate before calling
const HANDLE_RE = /^@?[A-Za-z0-9_]{1,15}$/;
if (!HANDLE_RE.test(rawUser)) throw new Error('not a valid X handle: ' + rawUser); Type guard
const isValidHandle = (s) => typeof s === 'string' && /^@?[A-Za-z0-9_]{1,15}$/.test(s.trim()); Try / catch
try {
await opencli.twitter.followers(user);
} catch (err) {
if (err.message.includes('must be a valid Twitter/X handle')) {
user = extractHandleFromUrl(user); // take last path segment
} else throw err;
} Prevention
- Pass bare handles, never profile URLs
- Trim whitespace and strip a single leading @ before calling
- Validate with the handle regex upstream in scripts
When it happens
Trigger: Passing user values like 'https://x.com/elonmusk', '@@double@', 'invalid name!', a full profile URL with query params, or any string with characters outside the allowed handle alphabet after trimming.
Common situations: Pasting a full profile URL instead of the handle; including trailing slashes or query strings; copying '@' plus whitespace; programmatic callers passing a display name instead of the handle.
Related errors
- ${label} is required
- ${label} must be a positive integer
- ${label} must be <= ${maxValue}
- arxiv ${label} must be a positive integer
- arxiv ${label} must be <= ${maxValue}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/5629143ac457a77e.
Report an issue: GitHub.