{"record":{"id":"eb7088680b7fee5d","repo":"jackwener/OpenCLI","slug":"failed-to-add-username-to-list-listid-memb-eb7088","errorCode":null,"errorMessage":"Failed to add @${username} to list ${listId}: member_count unchanged and membership was not confirmed","messagePattern":"Failed to add @(.+?) to list (.+?): member_count unchanged and membership was not confirmed","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/twitter/list-add-core.js","lineNumber":88,"sourceCode":"    if (!hasMemberCount) {\n        throw new CommandExecutionError(`Failed to add @${username} to list ${listId}: no member_count in response`);\n    }\n\n    const memberCountAfter = Number(addResult.mc);\n    if (!Number.isFinite(memberCountAfter)) {\n        throw new CommandExecutionError(`Failed to add @${username} to list ${listId}: invalid member_count in response`);\n    }\n\n    if (memberCountAfter < memberCountBefore) {\n        throw new CommandExecutionError(\n            `Failed to add @${username} to list ${listId}: member_count decreased unexpectedly (${memberCountBefore} → ${memberCountAfter})`\n        );\n    }\n\n    const countIncreased = memberCountAfter > memberCountBefore;\n    const noop = !countIncreased;\n    if (noop && addResult.isMember !== true) {\n        throw new CommandExecutionError(\n            `Failed to add @${username} to list ${listId}: member_count unchanged and membership was not confirmed`\n        );\n    }\n    const verifiedBy = `member_count ${memberCountBefore} → ${memberCountAfter}`;\n    return {\n        listId,\n        username,\n        userId: String(userId),\n        status: noop ? 'noop' : 'success',\n        message: noop\n            ? `@${username} is already a member of list ${listId}`\n            : `Added @${username} to list ${listId} (verified via ${verifiedBy})`,\n    };\n}\n\nexport async function listAddUser(page, kwargs) {\n        const listId = String(kwargs.listId || '').trim();\n        const username = String(kwargs.username || '').replace(/^@/, '').trim();","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/list-add-core.js#L70-L106","documentation":"A CommandExecutionError from buildListAddMemberRow thrown when the member_count did not increase (noop) and the response did not confirm isMember === true. This is the 'add silently did nothing' case: the mutation returned success-shaped data but neither the count nor an explicit membership flag proves the user was added.","triggerScenarios":"countIncreased === false and addResult.isMember !== true after the add — usually because the user was ALREADY a member (count unchanged) but the response also failed to set the isMember flag, or X returned an ambiguous payload.","commonSituations":"Idempotent re-run adding a user who is already in the list; X's GraphQL response omitting the isMember field due to schema drift; a soft-failed mutation that returned HTTP 200.","solutions":["Check whether @username is already in the list — if so, this add was a no-op and can be skipped.","Update the library so isMember is parsed from X's current response schema.","Retry once with a fresh session to get a payload that confirms membership explicitly.","If you intentionally tolerate duplicates, treat 'already a member' responses as success in your wrapper."],"exampleFix":"// before: blind re-add of an existing member\nawait listAddUser(page, { listId, username: 'alice' }); // throws\n// after: check membership first\nconst members = await listMembers(page, listId);\nif (!members.includes('alice')) await listAddUser(page, { listId, username: 'alice' });","handlingStrategy":"validation","validationCode":"// avoid the error entirely: skip users already in the list\nconst members = new Set(await listMemberUsernames(page, listId));\nconst pending = usernames.filter(u => !members.has(u.replace(/^@/, '')));","typeGuard":"function confirmsMembership(r) {\n  return r?.isMember === true;\n}","tryCatchPattern":"try {\n  await listAddUser(page, { listId, username });\n} catch (e) {\n  if (/member_count unchanged and membership was not confirmed/.test(e.message)) {\n    console.warn(`@${username} may already be in list ${listId}; skipping`);\n    return; // treat as idempotent success\n  }\n  throw e;\n}","preventionTips":["Check list membership before adding to avoid no-op re-adds.","Keep the library updated so isMember is parsed correctly from X's schema.","Design list-add pipelines to be idempotent — treat 'already a member' as success.","Retry once with a fresh session if the ambiguity is unexpected."],"tags":["twitter","graphql","verification-failed","cli"],"backgroundTag":"unconfirmed-operation-result","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}