jackwener/OpenCLI · warning · ArgumentError

Refusing to delete list without --confirm true

Error message

Refusing to delete list without --confirm true

What it means

Deleting a list is destructive and irreversible, so list-delete refuses to run unless the user explicitly passes --confirm true (validated via normalizeConfirm). This is a deliberate safety guard against accidental deletions.

Source

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

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

        const listsBefore = await getManagedLists(page, headers);
        const targetList = listsBefore.find((list) => list.id === listId);
        if (!targetList) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run with `--confirm true`
  2. Check normalizeConfirm's accepted truthy spellings and pass an exact match
  3. Update automation scripts to include the confirm flag

Example fix

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

Strategy: validation

Validate before calling

if (!/^(true|True)$/i.test(String(confirmArg))) throw new Error('list-delete requires --confirm true');

Type guard

function isConfirmed(v) {
  return v === true || v === 'true';
}

Try / catch

try {
  await page.func({ listId, confirm: 'true' });
} catch (e) {
  if (/Refusing to delete/.test(e.message)) {
    console.error('Destructive op requires explicit --confirm true');
  } else throw e;
}

Prevention

When it happens

Trigger: `twitter list-delete <id>` invoked without --confirm, with --confirm false, or with a value normalizeConfirm doesn't treat as true (e.g. 'yes', '1', 'y' if unsupported).

Common situations: Running the command interactively and forgetting the flag; scripts written before the confirm requirement existed; automation passing confirm:"True" in a casing/format the normalizer rejects.

Related errors


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