yikart/AiToEarn · error · BadRequestException
搜索推文失败: ${error.response?.data?.error || error.message}
Error message
搜索推文失败: ${error.response?.data?.error || error.message} What it means
searchTweets queries the Twitter API v2 recent-search endpoint with a Bearer token and returns response.data. Axios-level failures are rethrown as BadRequestException with Twitter's error detail (error.response.data.error) or the Axios message.
Source
Thrown at project/aitoearn-electron/server/src/modules/plat/twitter/twitter.service.ts:308
'max_results': isNaN(validMaxResults) ? 10 : validMaxResults, // 如果是NaN则使用默认值10
'tweet.fields': 'created_at,public_metrics,text',
'expansions': 'attachments.media_keys',
'media.fields': 'url,preview_image_url,type'
};
const response = await lastValueFrom(
this.httpService.get(url, {
params,
headers: {
'Authorization': `Bearer ${accessToken}`
}
})
);
return response.data;
} catch (error) {
this.logger.error(`搜索推文失败: ${error.message}`, error.stack);
throw new BadRequestException(`搜索推文失败: ${error.response?.data?.error || error.message}`);
}
}
/**
* 对推文点赞
* @param accessToken 访问令牌
* @param userId 用户ID
* @param accountId Twitter账号ID
* @param tweetId 推文ID
* @returns 点赞结果
*/
async likeTweet(accessToken: string, userId: string, accountId: string, tweetId: string) {
try {
// Twitter API V2 点赞端点
const url = `${TWITTER_API_V2_URL}/users/${accountId}/likes`;
const data = {
tweet_id: tweetId
};View on GitHub (pinned to d3aa8bea5b)
Solutions
- Validate/encode the search query: escape quotes, remove unsupported operators, respect the char limit.
- Confirm your API project tier includes recent search (Essential/Pro); upgrade if 403 'client-not-enrolled' appears.
- Refresh the access token on 401 errors.
- Use an app-only Bearer token for recent search if user context is not required.
- Back off and retry on 429 using the x-rate-limit-reset header.
Example fix
// before
const q = `from: ${user} "new post"`
const res = await twitterService.searchTweets(accessToken, userId, q)
// after
const q = `from:${userHandle} "new post"`.slice(0, 512)
if (!q.trim()) throw new Error('empty query')
const res = await twitterService.searchTweets(accessToken, userId, q) Defensive patterns
Strategy: validation
Validate before calling
function isValidSearchQuery(q: string): boolean {
return typeof q === 'string' && q.trim().length > 0 && q.length <= 512 &&
(q.split('"').length - 1) % 2 === 0 // balanced quotes
} Type guard
const hasValidQuery = (q: unknown): q is string => typeof q === 'string' && q.trim().length > 0 && q.length <= 512
Try / catch
if (!hasValidQuery(query)) throw new Error('invalid search query')
try {
return await twitterService.searchTweets(accessToken, userId, query)
} catch (e) {
if (/invalid query|400/i.test(String(e.message))) throw new Error(`query rejected by Twitter: ${query}`)
if (/429/.test(String(e.message))) { await sleep(16000); return retry() }
throw e
} Prevention
- Sanitize user-provided search strings (escape quotes, drop unsupported operators)
- Use app-only Bearer token for recent search when user context isn't needed
- Check API tier access to recent search before shipping the feature
- Cache search results to reduce rate-limit pressure
When it happens
Trigger: Malformed query operators in the search string (400 Invalid query, e.g. unbalanced quotes or invalid operator), expired token (401), using user-context token where app-only is required or vice versa (403), recent search only covering the last 7 days, or 429 rate limiting.
Common situations: Users typing raw hashtags/keywords with unsupported operators; free tier lacking recent search access entirely; hitting the very low free-tier rate limit; query longer than 512/1024 char limit.
Related errors
- 删除推文失败: ${error.response?.data?.error || error.message}
- 获取推文详情失败: ${error.response?.data?.error || error.message}
- 获取推文统计数据失败: ${error.response?.data?.error || error.message}
- 点赞推文失败: ${error.response?.data?.error || error.message}
- 取消点赞推文失败: ${error.response?.data?.error || error.message}
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/1cc4cb8cf8f89630.
Report an issue: GitHub.