jackwener/OpenCLI · error · CommandExecutionError
List ${listId} not found among your lists (${parsedLists.len
Error message
List ${listId} not found among your lists (${parsedLists.length} lists fetched). What it means
After fetching ListsManagementPageTimeline, the command parses your lists and looks for one whose id equals the supplied listId. If the list is absent from the parsed result, it throws CommandExecutionError including how many lists were fetched, since adding a member requires the target list to exist and be owned/manageable by the logged-in account.
Source
Thrown at clis/twitter/list-add-core.js:163
const listsQueryId = await resolveTwitterQueryId(page, 'ListsManagementPageTimeline', LISTS_MANAGEMENT_QUERY_ID);
const listsUrl = `/i/api/graphql/${listsQueryId}/ListsManagementPageTimeline?features=${encodeURIComponent(JSON.stringify(LISTS_MANAGEMENT_FEATURES))}`;
const listsDataRaw = await page.evaluate(`async () => {
const r = await fetch(${JSON.stringify(listsUrl)}, { headers: ${headers}, credentials: 'include' });
if (!r.ok) return { __error: 'HTTP ' + r.status };
return await r.json();
}`);
// Don't unwrap listsData: opencli spreads GraphQL response to top-level + adds session;
// parseListsManagement reads `.data.viewer.*` from this shape directly.
const listsData = listsDataRaw;
const parsedLists = listsData && !listsData.__error
? parseListsManagement(listsData, new Set())
: [];
if (listsData && listsData.__error) {
throw new CommandExecutionError(`Could not fetch lists: ${listsData.__error}`);
}
const targetList = parsedLists.find((l) => l.id === listId);
if (!targetList) {
throw new CommandExecutionError(`List ${listId} not found among your lists (${parsedLists.length} lists fetched).`);
}
// Direct GraphQL ListAddMember mutation.
//
// Previously this command opened the X profile, clicked "…" → "Add/remove from Lists",
// navigated the dialog and used nativeClick on the Save button. In 2026-05 X replaced
// the dialog with a full-page route (/i/lists/add_member), breaking that UI flow.
//
// The mutation is the same one the UI fires under the hood; calling it directly is
// both more reliable and ~10x faster (no goto-profile + scroll-dialog roundtrip).
const memberCountBefore = Number(targetList.members) || 0;
const listAddMemberQueryId = await resolveTwitterQueryId(page, 'ListAddMember', LIST_ADD_MEMBER_QUERY_ID);
const addUrl = `/i/api/graphql/${listAddMemberQueryId}/ListAddMember`;
const addBody = JSON.stringify({
variables: { listId, userId: String(userId) },
queryId: listAddMemberQueryId,
});
const addResultJsonRaw = await page.evaluate(`async () => {View on GitHub (pinned to 49907e53dc)
Solutions
- Print your list ids (e.g. via a list-list command or the ListsManagementPageTimeline response) and copy the exact numeric id.
- Confirm you are logged into the account that owns the list.
- Verify the list still exists at https://x.com/i/lists/<listId> (it may have been deleted).
- If you own many lists and the count looks truncated, scroll/load more lists in the web UI or page through the timeline to refresh the cached set.
Example fix
// before opencli twitter list-add 123456781 alice CommandExecutionError: List 123456781 not found among your lists (12 lists fetched). // after opencli twitter list-add 123456789 alice
Defensive patterns
Strategy: validation
Validate before calling
const parsedLists = parseListsManagement(await fetchLists(), new Set());
if (!parsedLists.some((l) => l.id === listId)) {
throw new Error(`List ${listId} is not owned by this account. Available ids: ${parsedLists.map((l) => l.id).join(', ')}`);
} Type guard
function listExists(parsedLists, listId) {
return Array.isArray(parsedLists) && parsedLists.some((l) => String(l.id) === String(listId));
} Try / catch
try {
await listAddUser(page, { listId, username });
} catch (e) {
if (/not found among your lists/.test(e.message)) {
console.error('Wrong listId or wrong logged-in account; list your lists and retry with the exact numeric id.');
return;
}
throw e;
} Prevention
- Copy list ids from the owning account's list page (x.com/i/lists/<id>), never from memory.
- Confirm which account the CLI browser profile is logged into before runs.
- Store list ids in config keyed by owning account.
- Check the list hasn't been deleted before batch operations.
When it happens
Trigger: Calling list-add with a numeric listId that is not among the lists returned by ListsManagementPageTimeline for the logged-in user (message reports parsedLists.length lists fetched).
Common situations: Typo or transposed digits in the listId; the list belongs to another account (X lists are manageable by their owner); the list was deleted; the list is private and you are logged into a different account; pagination truncated the list set so it wasn't in the fetched page.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Could not resolve user @${username}
- ${probe.detail}
- twitter_collection_request_error
- device_follow
- Twitter UserMedia returned GraphQL errors: ${JSON.stringify(
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/91e3a5da6d232b23.
Report an issue: GitHub.