jackwener/OpenCLI · error · CommandExecutionError
Failed to add @${username} to list ${listId}: ${msg.slice(0,
Error message
Failed to add @${username} to list ${listId}: ${msg.slice(0, 300)} What it means
A CommandExecutionError from buildListAddMemberRow thrown when the HTTP call succeeded but the GraphQL response contained fatal errors and no member_count. The library deliberately ignores partial GraphQL errors (e.g. on default_banner_media_results) that X returns even on success; only when the main data (member_count) is missing AND fatal errors exist does it fail, with the first 300 chars of the joined error messages.
Source
Thrown at clis/twitter/list-add-core.js:68
&& !/decode/i.test(e?.message || '')
);
}
export function buildListAddMemberRow({ addResult, memberCountBefore, listId, username, userId }) {
if (!addResult?.httpOk) {
throw new CommandExecutionError(
`Failed to add @${username} to list ${listId}: HTTP ${addResult?.status ?? 0}${addResult?.fetchError ? ' (' + addResult.fetchError + ')' : ''}${addResult?.raw ? ' — ' + addResult.raw : ''}`
);
}
// X often returns a partial GraphQL error on `default_banner_media_results`
// 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;View on GitHub (pinned to 49907e53dc)
Solutions
- Read the embedded GraphQL error message(s) in the error text — they name the real cause (permissions, rate limit, etc.).
- Verify the authenticated account owns the list before mutating.
- Refresh session cookies if the error indicates unauthorized access.
- Back off and retry if the error indicates rate limiting or temporary unavailability.
Example fix
// before: mutating a list owned by someone else
await listAddUser(page, { listId: '999999999', username: 'alice' });
// after: only mutate your own list
const myListIds = await fetchOwnedLists(page);
if (myListIds.includes('999999999')) await listAddUser(page, { listId: '999999999', username: 'alice' }); Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
function hasFatalGraphqlErrors(r) {
return Array.isArray(r?.errors) && r.errors.some(e => e && typeof e.message === 'string');
} Try / catch
try {
await listAddUser(page, { listId, username });
} catch (e) {
if (/Failed to add @/.test(e.message)) {
// message contains the first 300 chars of the GraphQL error(s)
console.error('GraphQL error from X:', e.message);
if (/unauthorized|forbidden/i.test(e.message)) await refreshSessionCookies(page);
if (/rate/i.test(e.message)) await sleep(15 * 60_000);
}
throw e;
} Prevention
- Only mutate lists you own.
- Check the embedded GraphQL error text — it names the real cause.
- Back off on rate-limit errors before retrying.
- Keep the library updated for X GraphQL schema changes.
When it happens
Trigger: addResult.mc is null/undefined and fatalGraphqlErrors(addResult.errors) is non-empty — i.e. X returned a real GraphQL error payload (e.g. unauthorized, rate-limited mutation, list not found) for the add-member mutation.
Common situations: Adding to a list you do not own; GraphQL-level account restrictions; X returning a substantive error for the mutation despite HTTP 200.
Related errors
- ${probe.detail}
- twitter_collection_request_error
- Twitter UserByScreenName returned GraphQL errors: ${JSON.str
- Failed to add @${username} to list ${listId}: no member_coun
- Failed to add @${username} to list ${listId}: invalid member
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/c73472e27f1d1c3c.
Report an issue: GitHub.