jackwener/OpenCLI · error · AuthRequiredError

Could not detect logged-in user. Are you logged in?

Error message

Could not detect logged-in user. Are you logged in?

What it means

When no username was given and the logged-in default is allowed, the helper navigates to x.com/home and reads the profile link `a[data-testid="AppTabBar_Profile_Link"]` to detect the current user. If the link is absent/not a string, or its href does not normalize to a valid handle, it throws this AuthRequiredError for x.com. The library cannot determine who is logged in, which almost always means there is no usable authenticated session.

Source

Thrown at clis/twitter/user-timeline.js:180

        throw new ArgumentError(
            `twitter ${commandName} username must be a valid Twitter/X handle`,
            commandName === 'collection'
                ? 'Example: opencli twitter collection @jack --until 2026-07-23T00:00:00Z'
                : 'Example: opencli twitter tweets @jack --limit 20',
        );
    }
    if (!username && !allowLoggedInDefault) {
        throw new ArgumentError('twitter collection username must be a valid Twitter/X handle', 'Example: opencli twitter collection @jack --until 2026-07-23T00:00:00Z');
    }
    if (!username) {
        await page.goto('https://x.com/home');
        await page.wait({ selector: '[data-testid="primaryColumn"]' });
        const href = unwrapBrowserResult(await page.evaluate(`() => {
            const link = document.querySelector('a[data-testid="AppTabBar_Profile_Link"]');
            return link ? link.getAttribute('href') : null;
        }`));
        if (!href || typeof href !== 'string') {
            throw new AuthRequiredError('x.com', 'Could not detect logged-in user. Are you logged in?');
        }
        username = normalizeTwitterScreenName(href);
        if (!username) {
            throw new AuthRequiredError('x.com', 'Could not detect logged-in user. Are you logged in?');
        }
    }

    const cookies = await page.getCookies({ url: 'https://x.com' });
    const ct0 = cookies.find((cookie) => cookie.name === 'ct0')?.value || null;
    if (!ct0) throw new AuthRequiredError('x.com', 'Not logged into x.com (no ct0 cookie)');

    const userTweetsOperation = await resolveTwitterOperationMetadata(page, 'UserTweets', USER_TWEETS_OPERATION);
    const userByScreenNameOperation = await resolveTwitterOperationMetadata(page, 'UserByScreenName', USER_BY_SCREEN_NAME_OPERATION);
    const headers = JSON.stringify({
        Authorization: `Bearer ${decodeURIComponent(TWITTER_BEARER_TOKEN)}`,
        'X-Csrf-Token': ct0,
        'X-Twitter-Auth-Type': 'OAuth2Session',
        'X-Twitter-Active-User': 'yes',

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log into x.com in the opencli browser session (`opencli browser login x.com` or manual login), then re-run without the username or pass one explicitly.
  2. Simplest workaround: pass the username explicitly (`opencli twitter tweets @jack`) so the logged-in detection path is skipped entirely.
  3. Verify the session by opening https://x.com/home in the managed browser and confirming the sidebar profile link exists.
  4. Clear stale cookies and re-login if the session is half-expired; check for X.com DOM testid changes if logged in but still failing.

Example fix

// before
opencli twitter tweets --limit 20        // no username, session expired -> AuthRequiredError
// after
opencli browser login x.com
opencli twitter tweets --limit 20        // or: opencli twitter tweets @me-handle --limit 20
Defensive patterns

Strategy: fallback

Validate before calling

// pre-check session before omitting the username
const loggedIn = await page.evaluate(`!!document.querySelector('[data-testid="AppTabBar_Profile_Link"]')`);
if (!loggedIn) {
  console.log('No logged-in x.com session; pass the username explicitly');
}

Type guard

function hasLoggedInSession(page) {
  return page !== null && typeof page.evaluate === 'function';
  // combined with runtime probe: await page.evaluate(`!!document.querySelector('a[data-testid="AppTabBar_Profile_Link"]')`)
}

Try / catch

try {
  await cli.run(['twitter', 'tweets', '--limit', '20']);
} catch (e) {
  if (e instanceof AuthRequiredError || /Could not detect logged-in user/.test(e.message)) {
    await ensureXLogin();
    await cli.run(['twitter', 'tweets', '--limit', '20']);
    // or fallback: cli.run(['twitter', 'tweets', explicitHandle, '--limit', '20'])
  } else throw e;
}

Prevention

When it happens

Trigger: Calling `twitter tweets`/`collection` without a username while the x.com session is logged out, expired, or showing a logged-out home layout without the AppTabBar profile link; the page renders but the href is null or unparseable.

Common situations: ct0/auth_token cookies expired; login wall or NOSCRIPT interstitial replacing the home DOM; X.com A/B test renaming the AppTabBar_Profile_Link testid; automation-detected logged-out state.

Related errors


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