jackwener/OpenCLI · error · ArgumentError

Invalid listId: ${JSON.stringify(kwargs.listId)}. Expected n

Error message

Invalid listId: ${JSON.stringify(kwargs.listId)}. Expected numeric ID.

What it means

The list-delete command requires listId to be a non-empty string of digits (Twitter list IDs are numeric). ArgumentError is thrown when listId is missing or contains non-numeric characters, before any network calls are made. This is a fail-fast input validation with a usage example attached.

Source

Thrown at clis/twitter/list-delete.js:88

cli({
    site: 'twitter',
    name: 'list-delete',
    access: 'write',
    description: 'Delete a Twitter/X list you own after explicit confirmation',
    domain: 'x.com',
    strategy: Strategy.UI,
    browser: true,
    args: [
        { name: 'listId', positional: true, type: 'string', required: true, help: 'Numeric ID of the list you own (e.g. from `opencli twitter lists`)' },
        { name: 'confirm', type: 'boolean', default: false, help: 'Required. Set --confirm true to delete the list.' },
        { name: 'timeout', type: 'int', default: 300, help: 'Max seconds for the overall delete command (default: 300)' },
    ],
    columns: ['listId', 'name', 'members', 'status', 'message'],
    func: async (page, kwargs) => {
        const listId = String(kwargs.listId || '').trim();
        if (!listId || !/^\d+$/.test(listId)) {
            throw new ArgumentError(`Invalid listId: ${JSON.stringify(kwargs.listId)}. Expected numeric ID.`, 'Example: opencli twitter list-delete 123456789 --confirm true');
        }
        if (!normalizeConfirm(kwargs.confirm)) {
            throw new ArgumentError('Refusing to delete list without --confirm true', 'Example: opencli twitter list-delete 123456789 --confirm true');
        }

        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 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)

Solutions

  1. Pass the numeric list ID, e.g. `opencli twitter list-delete 123456789 --confirm true`
  2. If you only know the list name, run `twitter list-manage`/list-list to look up its numeric id first
  3. Strip surrounding whitespace or URL prefixes from the ID before passing it
  4. Quote the argument in shells where it might be mangled

Example fix

// before
opencli twitter list-delete "MyList" --confirm true
// after
opencli twitter list-delete 123456789 --confirm true
Defensive patterns

Strategy: validation

Validate before calling

function isValidListId(v) {
  return typeof v === 'string' && /^\d+$/.test(v.trim());
}
if (!isValidListId(process.argv[3])) throw new Error('listId must be numeric');

Type guard

function isNumericListId(v) {
  return typeof v === 'string' && /^\d+$/.test(v);
}

Try / catch

try {
  await page.func({ listId: args.listId, confirm: 'true' });
} catch (e) {
  if (e instanceof ArgumentError && /Invalid listId/.test(e.message)) {
    console.error('Usage: opencli twitter list-delete <numeric-id> --confirm true');
  } else throw e;
}

Prevention

When it happens

Trigger: `twitter list-delete` called with an empty/undefined listId, a list slug or name instead of the numeric ID, or an ID containing whitespace/letters (e.g. 'abc', 'MyList', '').

Common situations: Passing the list's human-readable name or URL slug instead of its numeric ID; copy-pasting a URL fragment like 'i/lists/12345'; forgetting the positional argument entirely.

Related errors


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