jackwener/OpenCLI · error · ArgumentError

twitter list-add username is required

Error message

twitter list-add username is required

What it means

An ArgumentError from listAddUser thrown when kwargs.username is empty after stripping a leading '@' and trimming. The command needs the screen name of the user to add to the list, and raises with an example usage when it is absent.

Solutions

  1. Pass the target screen name: opencli twitter list-add 123456789 alice (leading '@' is optional and stripped).
  2. Validate that the username variable is non-empty in your script before invoking.
  3. If usernames come from a file/pipeline, filter out blank rows first.
  4. Confirm you are passing the username as its own argument and not being swallowed by a flag.

Example fix

// before
const users = ['alice', ''].filter(u => u.startsWith('@'));
await listAddUser(page, { listId, username: users[1] }); // '@'-less '' slips through
// after
const users = ['alice', ''].map(u => u.replace(/^@/, '')).filter(Boolean);
for (const u of users) await listAddUser(page, { listId, username: u });
Defensive patterns

Strategy: validation

Validate before calling

function toUsername(input) {
  const u = String(input ?? '').replace(/^@/, '').trim();
  if (!u) throw new Error('username is required');
  return u;
}
const usernames = rawList.map(toUsername).filter(Boolean);

Type guard

function isValidUsername(v) {
  return typeof v === 'string' && v.replace(/^@/, '').trim().length > 0;
}

Try / catch

try {
  await listAddUser(page, { listId, username });
} catch (e) {
  if (e instanceof ArgumentError && /username is required/.test(e.message)) {
    console.error('Provide a screen name: opencli twitter list-add 123456789 alice');
  }
  throw e;
}

Prevention

When it happens

Trigger: listAddUser called with username undefined/null, an empty string, or a value consisting solely of '@'.

Common situations: Forgetting the username argument on the CLI; a scripting variable left empty (e.g. from an unfilled CSV row or failed lookup); passing only '@' after the framework stripped the handle.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at clis/twitter/list-add-core.js:111

    return {
        listId,
        username,
        userId: String(userId),
        status: noop ? 'noop' : 'success',
        message: noop
            ? `@${username} is already a member of list ${listId}`
            : `Added @${username} to list ${listId} (verified via ${verifiedBy})`,
    };
}

export async function listAddUser(page, kwargs) {
        const listId = String(kwargs.listId || '').trim();
        const username = String(kwargs.username || '').replace(/^@/, '').trim();
        if (!listId || !/^\d+$/.test(listId)) {
            throw new ArgumentError(`Invalid listId: ${JSON.stringify(kwargs.listId)}. Expected numeric ID.`, 'Example: opencli twitter list-add 123456789 alice');
        }
        if (!username) {
            throw new ArgumentError('twitter list-add username is required', 'Example: opencli twitter list-add 123456789 alice');
        }
        // Strategy.UI does not get a domain URL pre-nav from the framework.
        // This page context is load-bearing for pre-target GraphQL calls below.
        await page.goto('https://x.com');
        await page.wait(3);
        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)');

        const userByScreenNameQueryId = await resolveTwitterQueryId(page, 'UserByScreenName', USER_BY_SCREEN_NAME_QUERY_ID);

        const headers = JSON.stringify({
            'Authorization': `Bearer ${decodeURIComponent(TWITTER_BEARER_TOKEN)}`,
            'X-Csrf-Token': ct0,
            'X-Twitter-Auth-Type': 'OAuth2Session',
            'X-Twitter-Active-User': 'yes',
        });

View on GitHub (pinned to 49907e53dc)