jackwener/OpenCLI · error · CommandExecutionError

HTTP ${userLookup.error}: Failed to resolve Twitter user @${

Error message

HTTP ${userLookup.error}: Failed to resolve Twitter user @${targetUser}

What it means

CommandExecutionError thrown when the UserByScreenName lookup fails with an HTTP status other than 401/403 (which are handled as auth errors). The message embeds the actual status code and the target screen name, indicating the request to resolve the user's numeric rest_id failed for a non-auth reason.

Source

Thrown at clis/twitter/following.js:201

        const headers = {
            'Authorization': `Bearer ${decodeURIComponent(TWITTER_BEARER_TOKEN)}`,
            'X-Csrf-Token': ct0,
            'X-Twitter-Auth-Type': 'OAuth2Session',
            '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));

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the screen name is correct and well-formed (e.g. @elonmusk, no spaces)
  2. Check the HTTP code in the message: 429 means rate limited — wait and retry; 400/404 means the user or query is invalid
  3. Update opencli to refresh Twitter query IDs via resolveTwitterQueryId
  4. Retry later if the code is 5xx (Twitter-side outage)

Example fix

// before: bad screen name -> HTTP 400
$ opencli twitter following '@elon musk'
Error: HTTP 400: Failed to resolve Twitter user @@elon musk
// after
$ opencli twitter following @elonmusk
Defensive patterns

Strategy: try-catch

Validate before calling

function validateHandle(user) {
  const m = /^@?([A-Za-z0-9_]{1,15})$/.exec((user || '').trim());
  if (!m) throw new Error(`Invalid Twitter handle: ${user}`);
  return m[1];
}

Type guard

function isTransientHttpStatus(err) {
  const m = /HTTP (\d{3})/.exec(String(err && err.message));
  return !!m && (m[1].startsWith('5') || m[1] === '429');
}

Try / catch

try {
  await cli.following(target);
} catch (err) {
  const code = (/(\d{3})/.exec(err.message) || [])[1];
  if (code === '429') { await sleep(60000); return retry(target); }
  if (code && code[0] === '5') { await sleep(5000); return retry(target, 2); }
  throw err; // 400/404: bad handle or stale query ID — update CLI
}

Prevention

When it happens

Trigger: The in-page fetch of buildUserByScreenNameQueryUrl(userByScreenNameQueryId, targetUser) returns a status like 400, 404, 429, or 5xx; userLookup.error is truthy but not 401/403, so describe falls to this generic CommandExecutionError.

Common situations: Passing a malformed or nonexistent screen name (400/404); rate limiting after many rapid commands (429); stale hardcoded FOLLOWING/USER_BY_SCREEN_NAME query IDs producing 400; Twitter server-side 5xx incidents.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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