{"record":{"id":"91e3a5da6d232b23","repo":"jackwener/OpenCLI","slug":"list-listid-not-found-among-your-lists-parse","errorCode":null,"errorMessage":"List ${listId} not found among your lists (${parsedLists.length} lists fetched).","messagePattern":"List (.+?) not found among your lists \\((.+?) lists fetched\\)\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/list-add-core.js","lineNumber":163,"sourceCode":"        const listsQueryId = await resolveTwitterQueryId(page, 'ListsManagementPageTimeline', LISTS_MANAGEMENT_QUERY_ID);\n        const listsUrl = `/i/api/graphql/${listsQueryId}/ListsManagementPageTimeline?features=${encodeURIComponent(JSON.stringify(LISTS_MANAGEMENT_FEATURES))}`;\n        const listsDataRaw = await page.evaluate(`async () => {\n            const r = await fetch(${JSON.stringify(listsUrl)}, { headers: ${headers}, credentials: 'include' });\n            if (!r.ok) return { __error: 'HTTP ' + r.status };\n            return await r.json();\n        }`);\n        // Don't unwrap listsData: opencli spreads GraphQL response to top-level + adds session;\n        // parseListsManagement reads `.data.viewer.*` from this shape directly.\n        const listsData = listsDataRaw;\n        const parsedLists = listsData && !listsData.__error\n            ? parseListsManagement(listsData, new Set())\n            : [];\n        if (listsData && listsData.__error) {\n            throw new CommandExecutionError(`Could not fetch lists: ${listsData.__error}`);\n        }\n        const targetList = parsedLists.find((l) => l.id === listId);\n        if (!targetList) {\n            throw new CommandExecutionError(`List ${listId} not found among your lists (${parsedLists.length} lists fetched).`);\n        }\n\n        // Direct GraphQL ListAddMember mutation.\n        //\n        // Previously this command opened the X profile, clicked \"…\" → \"Add/remove from Lists\",\n        // navigated the dialog and used nativeClick on the Save button. In 2026-05 X replaced\n        // the dialog with a full-page route (/i/lists/add_member), breaking that UI flow.\n        //\n        // The mutation is the same one the UI fires under the hood; calling it directly is\n        // both more reliable and ~10x faster (no goto-profile + scroll-dialog roundtrip).\n        const memberCountBefore = Number(targetList.members) || 0;\n        const listAddMemberQueryId = await resolveTwitterQueryId(page, 'ListAddMember', LIST_ADD_MEMBER_QUERY_ID);\n        const addUrl = `/i/api/graphql/${listAddMemberQueryId}/ListAddMember`;\n        const addBody = JSON.stringify({\n            variables: { listId, userId: String(userId) },\n            queryId: listAddMemberQueryId,\n        });\n        const addResultJsonRaw = await page.evaluate(`async () => {","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/list-add-core.js#L145-L181","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nopencli twitter list-add 123456781 alice\nCommandExecutionError: List 123456781 not found among your lists (12 lists fetched).\n// after\nopencli twitter list-add 123456789 alice","handlingStrategy":"validation","validationCode":"const parsedLists = parseListsManagement(await fetchLists(), new Set());\nif (!parsedLists.some((l) => l.id === listId)) {\n  throw new Error(`List ${listId} is not owned by this account. Available ids: ${parsedLists.map((l) => l.id).join(', ')}`);\n}","typeGuard":"function listExists(parsedLists, listId) {\n  return Array.isArray(parsedLists) && parsedLists.some((l) => String(l.id) === String(listId));\n}","tryCatchPattern":"try {\n  await listAddUser(page, { listId, username });\n} catch (e) {\n  if (/not found among your lists/.test(e.message)) {\n    console.error('Wrong listId or wrong logged-in account; list your lists and retry with the exact numeric id.');\n    return;\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["twitter","input-validation","graphql"],"backgroundTag":"resource-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}