jackwener/OpenCLI · error · ArgumentError

twitter list-remove username is required

Error message

twitter list-remove username is required

What it means

After validating listId, listRemoveUser normalizes kwargs.username (strips a leading '@') and requires a non-empty result, otherwise throwing ArgumentError 'twitter list-remove username is required' at list-remove-core.js:58. The username is needed both to resolve the user's numeric id via UserByScreenName and to navigate to their profile for the UI removal flow.

Source

Thrown at clis/twitter/list-remove-core.js:58

    responsive_web_enhance_cards_enabled: false,
};

export function interpretRemoveResponse(status, json) {
    if (status === 200 && json && (json.id_str || json.id || json.slug)) return { ok: true };
    if (json && Array.isArray(json.errors) && json.errors.length > 0) {
        const err = json.errors[0];
        return { ok: false, error: `${err.code ? '[' + err.code + '] ' : ''}${err.message || 'Unknown error'}` };
    }
    return { ok: false, error: `HTTP ${status}` };
}

export async function listRemoveUser(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.`);
        }
        if (!username) throw new ArgumentError('twitter list-remove username is required');

        // 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',
        });

        const userLookupUrl = buildUserByScreenNameQueryUrl(userByScreenNameQueryId, username);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Supply the screen name: `opencli twitter list-remove <numericListId> alice`
  2. Quote the '@' form if needed — '@alice' is accepted (the leading @ is stripped) — but ensure it isn't empty
  3. Check your shell: `opencli ... list-remove "$LIST_ID" "$USER"` and confirm USER isn't unset/empty (set -u helps)
  4. If calling listRemoveUser directly, pass kwargs = { listId: '123...', username: 'alice' } with both keys present
  5. Run `opencli twitter list-remove --help` to confirm the expected argument order for your version

Example fix

// before (empty variable)
opencli twitter list-remove 1734567890123456789 "$TARGET_USER"   # TARGET_USER unset -> ''
// after
: "${TARGET_USER:?TARGET_USER must be set}"
opencli twitter list-remove 1734567890123456789 "$TARGET_USER"
Defensive patterns

Strategy: validation

Validate before calling

function requireUsername(raw) {
  const u = String(raw ?? '').replace(/^@/, '').trim();
  if (!u) throw new Error('username is required for twitter list-remove');
  return u;
}
// call: await removeUser(listId, requireUsername(process.env.TARGET_USER));

Type guard

function hasUsername(kwargs) {
  return kwargs != null && typeof kwargs.username === 'string' && kwargs.username.replace(/^@/, '').trim().length > 0;
}

Try / catch

try {
  await run(`opencli twitter list-remove ${listId} ${username}`);
} catch (e) {
  if (e instanceof ArgumentError && /username is required/.test(e.message)) {
    // fix argument construction, then retry once
    if (!username) throw new Error('Caller bug: username was empty; resolve it before retrying');
    return run(`opencli twitter list-remove ${listId} ${username}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Invoking the list-remove command without the username argument; passing an empty string or only '@'; kwargs.username being undefined/null when called programmatically; a typo where the second positional argument was swallowed by shell quoting; passing the username in an option slot the CLI doesn't recognize so it never reaches kwargs.username.

Common situations: Forgetting the second positional arg in scripts; shell variables that expand to empty (USERNAME=''); assuming '@handle' alone is rejected when actually only an empty value is — the failure is passing '' or omitting it; CLI arg parsing differences that drop arguments starting with '@' (some tools treat @file specially).

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/34351d22f05800f5. Report an issue: GitHub.