jackwener/OpenCLI · error · CommandExecutionError

Could not find user @${targetUser}

Error message

Could not find user @${targetUser}

What it means

CommandExecutionError thrown when the UserByScreenName lookup succeeds (HTTP 200) but the response contains no user rest_id — d.data?.user?.result?.rest_id is null/undefined. This means Twitter did not return an account for the given screen name.

Source

Thrown at clis/twitter/following.js:205

            'X-Twitter-Active-User': 'yes',
        };

        // Get userId from screen_name
        const userLookup = unwrapBrowserResult(await page.evaluate(async (url, headers) => {
            const resp = await fetch(url, { headers, credentials: 'include' });
            if (!resp.ok) return { error: resp.status };
            const d = await resp.json();
            return { userId: d.data?.user?.result?.rest_id || null };
        }, buildUserByScreenNameQueryUrl(userByScreenNameQueryId, targetUser), headers));
        if (userLookup?.error === 401 || userLookup?.error === 403) {
            throw new AuthRequiredError('x.com', `Twitter user lookup failed (HTTP ${userLookup.error})`);
        }
        if (userLookup?.error) {
            throw new CommandExecutionError(`HTTP ${userLookup.error}: Failed to resolve Twitter user @${targetUser}`);
        }
        const userId = userLookup?.userId || null;
        if (!userId)
            throw new CommandExecutionError(`Could not find user @${targetUser}`);

        const allUsers = [];
        const seen = new Set();
        let cursor = null;
        let lastRawResponse = null;

        // Runaway guard only; --limit and cursor exhaustion control normal pagination.
        for (let i = 0; i < MAX_PAGINATION_PAGES && allUsers.length < limit; i++) {
            const fetchCount = Math.min(50, limit - allUsers.length + 10);
            const apiUrl = buildFollowingUrl(followingQueryId, userId, fetchCount, cursor);
            const data = unwrapBrowserResult(await page.evaluate(async (url, headers) => {
                const r = await fetch(url, { headers, credentials: 'include' });
                return r.ok ? await r.json() : { error: r.status };
            }, apiUrl, headers));
            if (data?.error) {
                if (data.error === 401 || data.error === 403)
                    throw new AuthRequiredError('x.com', `Twitter following request failed (HTTP ${data.error})`);
                throw new CommandExecutionError(describeTwitterApiError('Following', data.error));

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the handle exists by opening https://x.com/<name> in a browser
  2. Check for typos or recent renames of the account
  3. Retry after updating opencli if Twitter changed the response shape (rest_id path)
  4. Use the numeric user ID directly if the CLI supports it, bypassing the screen-name lookup

Example fix

// before: nonexistent handle
$ opencli twitter following @thisuserdoesnotexist12345
Error: Could not find user @thisuserdoesnotexist12345
// after: use a real, existing handle
$ opencli twitter following @elonmusk
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check that the handle exists before running the following command
const { execSync } = require('child_process');
const status = execSync(`curl -s -o /dev/null -w '%{http_code}' https://x.com/${handle.replace('@','')}`).trim();
if (status !== '200') throw new Error(`@${handle.replace('@','')} does not exist or is unavailable`);

Type guard

function lookupSucceeded(d) {
  return d && typeof d === 'object' && typeof d?.data?.user?.result?.rest_id === 'string' && d.data.user.result.rest_id.length > 0;
}

Try / catch

try {
  await cli.following(target);
} catch (err) {
  if (/Could not find user @/.test(err.message)) {
    console.error('Check the handle at https://x.com/' + target.replace('@','') + ' — it may be renamed, deleted, or suspended.');
  } else throw err;
}

Prevention

When it happens

Trigger: After a non-error API response, userId is falsy: the screen name does not exist, was renamed, or the account is suspended/removed, so the nested rest_id path resolves to null.

Common situations: Typo in the handle; the account was deleted, renamed, or suspended; requesting a protected/withheld account from a region where it is unavailable; Twitter changing the UserByScreenName response shape after an API update so rest_id sits at a different path.

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


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