yikart/AiToEarn · error · BadRequestException
获取推文统计数据失败: ${error.response?.data?.error || error.message}
Error message
获取推文统计数据失败: ${error.response?.data?.error || error.message} What it means
getTweetMetrics calls GET /2/tweets/:tweetId (with public_metrics fields) and returns response.data. Any failure from the Twitter API v2 call is wrapped in a BadRequestException, message taken from error.response.data.error or error.message.
Source
Thrown at project/aitoearn-electron/server/src/modules/plat/twitter/twitter.service.ts:270
const url = `${TWITTER_API_V2_URL}/tweets/${tweetId}`;
const params = {
'tweet.fields': 'public_metrics,non_public_metrics,organic_metrics', // 注意:某些指标需要高级API访问权限
};
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 userId 用户ID
* @param accountId Twitter账号ID
* @param query 查询内容
* @param maxResults 最大结果数
* @returns 搜索结果
*/
async searchTweets(accessToken, userId: string, accountId: string, query: string, maxResults: number = 10) {
try {
// 确保maxResults是一个有效的整数
const validMaxResults = Number(maxResults);
const url = `${TWITTER_API_V2_URL}/tweets/search/recent`;
const params = {View on GitHub (pinned to d3aa8bea5b)
Solutions
- Refresh the user access token on 401 and retry once.
- Honor 429: back off until rate-limit reset before calling again.
- Skip tweets that return 404 (deleted) instead of failing the whole batch.
- Verify public_metrics is requested in tweet.fields and your API tier allows it.
- Log error.response.data.errors for Twitter's precise error code.
Example fix
// before
const metrics = await twitterService.getTweetMetrics(accessToken, userId, accountId, tweetId)
// after
try {
const metrics = await twitterService.getTweetMetrics(accessToken, userId, accountId, tweetId)
} catch (e) {
if (String(e.message).includes('429')) await sleep(15000)
else if (/not found/i.test(e.message)) return null
else throw e
} Defensive patterns
Strategy: retry
Validate before calling
if (!accessToken) throw new Error('missing access token before getTweetMetrics') Type guard
const isRateLimited = (e: unknown): boolean => (e as any)?.response?.status === 429 || /429|rate limit/i.test(String((e as any)?.message))
Try / catch
const fetchMetrics = async (attempt = 0): Promise<any> => {
try {
return await twitterService.getTweetMetrics(accessToken, userId, accountId, tweetId)
} catch (e) {
if (isRateLimited(e) && attempt < 3) {
await sleep(15000 * 2 ** attempt)
return fetchMetrics(attempt + 1)
}
if (/not found/i.test(String(e.message))) return null
throw e
}
} Prevention
- Respect x-rate-limit-reset headers in batch metric jobs
- Space out metrics polling instead of tight loops
- Track token expiry and refresh before it lapses
- Skip deleted tweets instead of failing the batch
When it happens
Trigger: Expired or revoked user token (401), tweet not found/deleted (404), missing metrics field params for the access tier, or Twitter rate limit (429) on the metrics endpoint.
Common situations: Batch metric jobs hitting 429 rate limits; tracking metrics of tweets deleted by the author; old code calling after token rotation; free-tier access without metrics fields.
Related errors
- 获取Twitter时间线失败: ${error.response?.data?.error || error.messa
- 发布推文失败: ${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/e70f02f0a4ec840f.
Report an issue: GitHub.