jackwener/OpenCLI · warning · EmptyResultError

twitter likes

Error message

twitter likes

What it means

EmptyResultError with label 'twitter likes' thrown when the Likes API response has no timeline instructions and the payload looks like a private-timeline response while zero likes have been collected. Likes on X are only visible to the account owner, so the library distinguishes this expected privacy case from a generic protocol error.

Source

Thrown at clis/twitter/likes.js:316

            const currentCount = useOutputFile ? outputCount : allTweets.length;
            const remaining = fetchAll ? 100 : (limit - currentCount + 10);
            const fetchCount = Math.min(100, remaining);
            const apiUrl = buildLikesUrl(likesQueryId, userId, fetchCount, cursor);
            const data = unwrapBrowserResult(await page.evaluate(`async () => {
        const r = await fetch(${JSON.stringify(apiUrl)}, { headers: ${headers}, credentials: 'include' });
        return r.ok ? await r.json() : { error: r.status };
      }`));
            if (data?.error) {
                if ((useOutputFile ? outputCount : allTweets.length) === 0)
                    throw new CommandExecutionError(describeTwitterApiError('Likes', data.error));
                break;
            }
            lastRawResponse = data;
            const hasInstructions = Array.isArray(data?.data?.user?.result?.timeline_v2?.timeline?.instructions)
                || Array.isArray(data?.data?.user?.result?.timeline?.timeline?.instructions);
            if (!hasInstructions) {
                if (looksLikePrivateTwitterTimeline(data) && (useOutputFile ? outputCount : allTweets.length) === 0) {
                    throw new EmptyResultError('twitter likes', `No likes returned for @${username} (Likes are private by default on X; only the account owner can view their own likes)`);
                }
                throw new CommandExecutionError('twitter_likes_protocol_error: missing Likes timeline instructions');
            }
            const { tweets, nextCursor } = parseLikes(data, seen);
            if (useOutputFile) {
                appendJsonlRows(outputFile, tweets);
                outputCount += tweets.length;
            }
            else {
                allTweets.push(...tweets);
            }
            const pageComplete = !nextCursor;
            writeResumeFile(resumeFile, {
                cursor: pageComplete ? null : nextCursor,
                count: useOutputFile ? outputCount : allTweets.length,
                tweets: useOutputFile ? undefined : allTweets,
                updatedAt: new Date().toISOString(),
                complete: pageComplete,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log in as the account whose likes you want: only the owner can view their own Likes timeline.
  2. Confirm you passed your own @username, not another user's.
  3. If you own the account and still see this, re-authenticate (session may be downgraded to a logged-out/public view).
  4. Accept the limitation: X no longer exposes likes publicly for other accounts.

Example fix

// before
$ cli twitter likes @some celebrity   // private timeline -> EmptyResultError
// after
$ cli twitter likes @my_own_handle    // run as the account owner, logged in
Defensive patterns

Strategy: try-catch

Validate before calling

// only the account owner can see their likes: verify target === session user
const sessionUser = await getLoggedInHandle(page);
if (normalize(sessionUser) !== normalize(username)) {
  console.warn('Likes are private; only the account owner can fetch them.');
}

Type guard

function sameUser(a, b) { return typeof a === 'string' && typeof b === 'string' && a.replace(/^@/, '').toLowerCase() === b.replace(/^@/, '').toLowerCase(); }

Try / catch

try {
  await cli.twitter.likes({ username });
} catch (e) {
  if (e.name === 'EmptyResultError' && /private by default/.test(e.message)) {
    console.error(`Likes for ${username} are private; log in as the owner.`);
    return; // expected, not a bug
  }
  throw e;
}

Prevention

When it happens

Trigger: data has no data.user.result.timeline_v2.timeline.instructions (nor the legacy timeline path), looksLikePrivateTwitterTimeline(data) is true, and outputCount/allTweets.length === 0 at clis/twitter/likes.js:316.

Common situations: Fetching likes for an account other than the logged-in user (likes are private by default); the target user's likes are hidden; fetching your own likes while logged in as a different account.

Related errors


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