jackwener/OpenCLI · error · CommandExecutionError

CreateList returned a list payload without a numeric list id

Error message

CreateList returned a list payload without a numeric list id.

What it means

This CommandExecutionError is thrown by requireCreateListResult in clis/twitter/list-create.js:64 when the returned list object exists but lacks an id that matches /^\d+$/. Twitter list ids are numeric (id_str or id); the library requires one to hand back a usable listId. It protects callers from using a malformed or missing identifier.

Source

Thrown at clis/twitter/list-create.js:64

    }
    if (!result.ok) {
        const snippet = String(result.bodyText || '').slice(0, 300);
        throw new CommandExecutionError(`HTTP ${result.httpStatus} from CreateList: ${snippet}`);
    }
    if (!result.bodyJson || typeof result.bodyJson !== 'object') {
        throw new CommandExecutionError(`CreateList returned malformed JSON payload. Body: ${String(result.bodyText || '').slice(0, 300)}`);
    }
    const list = result.bodyJson?.data?.list;
    if (!list || typeof list !== 'object') {
        const errors = result.bodyJson?.errors;
        if (Array.isArray(errors) && errors.length > 0) {
            throw new CommandExecutionError(`CreateList failed: ${errors[0].message || JSON.stringify(errors[0])}`);
        }
        throw new CommandExecutionError(`CreateList returned no list payload. Body: ${String(result.bodyText || '').slice(0, 300)}`);
    }
    const id = String(list.id_str || list.id || '');
    if (!/^\d+$/.test(id)) {
        throw new CommandExecutionError('CreateList returned a list payload without a numeric list id.');
    }
    if (typeof list.name !== 'string' || !list.name.trim()) {
        throw new CommandExecutionError('CreateList returned a list payload without a list name.');
    }
    if (list.name.trim() !== expectedName) {
        throw new CommandExecutionError(`CreateList returned name ${JSON.stringify(list.name)}, expected ${JSON.stringify(expectedName)}.`);
    }
    const modeValue = typeof list.mode === 'string' ? list.mode : '';
    if (!modeValue) {
        throw new CommandExecutionError('CreateList returned a list payload without list mode.');
    }
    const mode = /private/i.test(modeValue) ? 'private' : 'public';
    if (mode !== expectedMode) {
        throw new CommandExecutionError(`CreateList returned mode ${mode}, expected ${expectedMode}.`);
    }
    return { createdList: list, listId: id, listMode: mode };
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log/inspect the full list payload (the error deliberately omits it) to see which id fields Twitter actually returned.
  2. If Twitter changed the field name/format, update the extraction in clis/twitter/list-create.js:62 (currently `list.id_str || list.id`) to the new field.
  3. Verify you are talking to the real x.com API and not a stub/mock environment returning non-numeric ids.
  4. Check whether the list exists on x.com and, if created, retrieve its numeric id from the UI or a ListLatest/ListByRequest query.
  5. Retry creation only after confirming no list was actually created, to avoid duplicates.

Example fix

// before
const id = String(list.id_str || list.id || '');
// after (if Twitter adds a new id field)
const id = String(list.id_str || list.id || list.rest_id || '');
Defensive patterns

Strategy: type-guard

Validate before calling

// Guard the id fields before trusting the returned list id:
function hasNumericListId(list) {
  const id = String(list?.id_str || list?.id || '');
  return /^\d+$/.test(id);
}

Type guard

function hasNumericListId(list) {
  const raw = list && (list.id_str ?? list.id);
  return typeof raw === 'string' || typeof raw === 'number'
    ? /^\d+$/.test(String(raw))
    : false;
}

Try / catch

try {
  const row = await opencli twitter list-create name;
} catch (err) {
  if (/without a numeric list id/.test(err.message)) {
    // inspect the raw payload / verify the list on x.com; do not use a fabricated id
    reportFatal('CreateList returned a list without a usable numeric id');
  } else throw err;
}

Prevention

When it happens

Trigger: data.list present but both id_str and id are missing, null, non-numeric (e.g. a base64 GraphQL cursor-style id), or empty string — typically a response schema change or a partially populated list object.

Common situations: Twitter changing CreateList to return a different id field name or format; a mock/test server returning a stub list without numeric ids; future GraphQL versions returning string-encoded ids instead of numeric id_str.

Related errors


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