jackwener/OpenCLI · error · CommandExecutionError

Failed to add @${username} to list ${listId}: member_count d

Error message

Failed to add @${username} to list ${listId}: member_count decreased unexpectedly (${memberCountBefore} → ${memberCountAfter})

What it means

A CommandExecutionError from buildListAddMemberRow thrown when the list's member_count after the add is LOWER than before. An add operation can never reduce the count, so this is treated as verification failure — the mutation likely did not apply as intended or the counts were read from inconsistent states.

Source

Thrown at clis/twitter/list-add-core.js:80

    // even on successful mutations. Treat only missing main data or non-decode
    // GraphQL errors as command failures.
    const hasMemberCount = addResult.mc !== null && addResult.mc !== undefined;
    const fatalErrors = fatalGraphqlErrors(addResult.errors);
    if (!hasMemberCount && fatalErrors.length) {
        const msg = fatalErrors.map((e) => e.message || JSON.stringify(e)).join('; ');
        throw new CommandExecutionError(`Failed to add @${username} to list ${listId}: ${msg.slice(0, 300)}`);
    }
    if (!hasMemberCount) {
        throw new CommandExecutionError(`Failed to add @${username} to list ${listId}: no member_count in response`);
    }

    const memberCountAfter = Number(addResult.mc);
    if (!Number.isFinite(memberCountAfter)) {
        throw new CommandExecutionError(`Failed to add @${username} to list ${listId}: invalid member_count in response`);
    }

    if (memberCountAfter < memberCountBefore) {
        throw new CommandExecutionError(
            `Failed to add @${username} to list ${listId}: member_count decreased unexpectedly (${memberCountBefore} → ${memberCountAfter})`
        );
    }

    const countIncreased = memberCountAfter > memberCountBefore;
    const noop = !countIncreased;
    if (noop && addResult.isMember !== true) {
        throw new CommandExecutionError(
            `Failed to add @${username} to list ${listId}: member_count unchanged and membership was not confirmed`
        );
    }
    const verifiedBy = `member_count ${memberCountBefore} → ${memberCountAfter}`;
    return {
        listId,
        username,
        userId: String(userId),
        status: noop ? 'noop' : 'success',
        message: noop

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Rerun the command — with a consistent read the count should be >= before.
  2. Ensure no other process/session is mutating the same list concurrently.
  3. Add a short delay between reading the before-count and the mutation, and verify the after-count comes from the mutation response itself.
  4. Check whether the target list was deleted, cleared, or its ownership changed.

Example fix

// before: long gap between count read and mutation lets count drift
const before = await getMemberCount(page);
await slowOtherWork();
await listAddUser(page, { listId, username });
// after: do them back-to-back
const before = await getMemberCount(page);
await listAddUser(page, { listId, username });
Defensive patterns

Strategy: retry

Validate before calling

null

Try / catch

try {
  return await listAddUser(page, { listId, username });
} catch (e) {
  if (/member_count decreased unexpectedly/.test(e.message)) {
    // likely a stale/racing count read: rerun with a fresh before-count
    await sleep(10_000);
    return listAddUser(page, { listId, username });
  }
  throw e;
}

Prevention

When it happens

Trigger: memberCountAfter < memberCountBefore after an add — typically caused by reading the before-count long before the mutation and something else removing members, or reading the after-count from a stale/cached response.

Common situations: Another session/process removing members concurrently; X serving a stale cached count; a race between two automated list operations.

Related errors


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