moeru-ai/airi · error
Like button not found
Error message
Like button not found
What it means
Thrown by likeTweet when page.$(SELECTORS.TIMELINE.LIKE_BUTTON) returns null — after the tweet page loaded (waitForSelector for the tweet passed) but the like button element was not found in the DOM. This is a plain Error, distinct from the surrounding catch-all (it is thrown inside the try, so it gets re-wrapped by the 'Failed to like tweet' catch).
Source
Thrown at integrations/twitter-services/src/core/services/tweet.ts:117
}
catch (error: unknown) {
console.error('Error searching tweets:', error)
throw new Error(`Failed to search tweets: ${errorToMessage(error)}`)
}
}
/**
* Likes a tweet with the given ID
*/
async function likeTweet(tweetId: string): Promise<boolean> {
try {
const page = ctx.page
await page.goto(`${TWITTER_BASE_URL}/i/status/${tweetId}`)
await page.waitForSelector(SELECTORS.TIMELINE.TWEET)
const likeButton = await page.$(SELECTORS.TIMELINE.LIKE_BUTTON)
if (!likeButton) {
throw new Error('Like button not found')
}
// Check if already liked
const isAlreadyLiked = await page.$eval(
SELECTORS.TIMELINE.LIKE_BUTTON,
el => el.getAttribute('aria-pressed') === 'true',
)
if (!isAlreadyLiked) {
await likeButton.click()
// Wait for the like to register
await page.waitForFunction(
`document.querySelector('${SELECTORS.TIMELINE.LIKE_BUTTON}')?.getAttribute('aria-pressed') === 'true'`,
{ timeout: 5000 },
)
}
return trueView on GitHub (pinned to 27111382b4)
Solutions
- Update SELECTORS.TIMELINE.LIKE_BUTTON to the current X data-testid (commonly '[data-testid="like"]').
- Verify the tweetId resolves to an existing, viewable tweet.
- Ensure the session is authenticated and the tweet is not protected/age-restricted.
- Re-query the button with a short waitForSelector(LIKE_BUTTON) before page.$ to handle render lag.
Example fix
// before
const likeButton = await page.$(SELECTORS.TIMELINE.LIKE_BUTTON)
if (!likeButton) {
throw new Error('Like button not found')
}
// after — wait for the button and confirm the tweet is viewable
await page.waitForSelector(SELECTORS.TIMELINE.LIKE_BUTTON, { timeout: 5000 })
const likeButton = await page.$(SELECTORS.TIMELINE.LIKE_BUTTON)
if (!likeButton) {
throw new Error('Like button not found (tweet may be unavailable)')
} Defensive patterns
Strategy: validation
Validate before calling
await page.waitForSelector(SELECTORS.TIMELINE.LIKE_BUTTON, { timeout: 5000 })
const likeButton = await page.$(SELECTORS.TIMELINE.LIKE_BUTTON)
if (!likeButton) throw new Error('Like button not found (tweet may be unavailable)') Type guard
function isLikeButtonNotFoundError(e: unknown): boolean {
// Note: likeTweet wraps this into 'Failed to like tweet: Like button not found'
return e instanceof Error && /Like button not found/.test(e.message)
} Try / catch
try {
await tweetServices.tweet.likeTweet(tweetId)
} catch (e) {
if (e instanceof Error && /Like button not found/.test(e.message)) {
// update SELECTORS.TIMELINE.LIKE_BUTTON or verify the tweet is viewable
} else throw e
} Prevention
- Update LIKE_BUTTON selector to the current X data-testid when the UI changes.
- Verify the tweetId is valid, existing, and viewable before liking.
- Ensure the session is authenticated so the action row renders.
- waitForSelector on the like button before querying it to absorb render lag.
When it happens
Trigger: Navigating to /i/status/<tweetId> where the tweet node renders but the like-button selector does not match: SELECTORS.TIMELINE.LIKE_BUTTON is stale after an X UI change; the tweet is protected/deleted so the action row is absent; the page shows a 'This post is unavailable' state; ARIA/aria-pressed attribute moved to a nested element.
Common situations: X redesigned the action bar so the data-testid/selector changed; tweet id is invalid or belongs to a deleted/protected post; the logged-in session lacks permission to see the action row; slow render meant the button existed but page.$ ran before paint (rare, since waitForSelector for TWEET already passed).
Related errors
- Retweet button not found
- Failed to search tweets: ${errorToMessage(error)}
- Failed to like tweet: ${errorToMessage(error)}
- Tweet ID is empty. Please provide a tweet ID to like.
- Tweet text is empty. Please provide text to post.
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/a35af2dc1afa3772.
Report an issue: GitHub.