yikart/AiToEarn · error · BadRequestException
删除推文失败: ${error.response?.data?.error || error.message}
Error message
删除推文失败: ${error.response?.data?.error || error.message} What it means
deleteTweet calls DELETE https://api.twitter.com/2/tweets/:tweetId with a Bearer user token. Any Axios error from Twitter API v2 (HTTP 4xx/5xx) is caught and rethrown as a NestJS BadRequestException with the message taken from error.response.data.error (the Twitter error detail) or error.message. It is a wrapped upstream Twitter API failure, not a local validation error.
Source
Thrown at project/aitoearn-electron/server/src/modules/plat/twitter/twitter.service.ts:206
async deleteTweet(accessToken, userId: string, accountId: string, tweetId: string) {
try {
const url = `${TWITTER_API_V2_URL}/tweets/${tweetId}`;
await lastValueFrom(
this.httpService.delete(url, {
headers: {
'Authorization': `Bearer ${accessToken}`
}
})
);
this.logger.log(`成功删除推文: tweetId=${tweetId}, accountId=${accountId}`);
return true
} 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 tweetId 推文ID
* @returns 推文详情
*/
async getTweetDetail(accessToken, userId: string, accountId: string, tweetId: string) {
try {
const url = `${TWITTER_API_V2_URL}/tweets/${tweetId}`;
const params = {
'tweet.fields': 'created_at,public_metrics,text,source',
'expansions': 'attachments.media_keys,author_id',
'media.fields': 'url,preview_image_url,type'View on GitHub (pinned to d3aa8bea5b)
Solutions
- Refresh the user's Twitter access token via TwitterAuthService before retrying (401 means expired).
- Verify the tweetId exists and belongs to accountId by calling GET /2/tweets/:id first.
- Ensure the OAuth2 token was issued with tweet.delete (tweet.write) scope and is a user-context token, not app-only Bearer.
- Inspect error.response.data (Twitter returns details/errors arrays) in the logged stack for the exact reason.
- Retry with exponential backoff only for 429/5xx; treat 403/404 as permanent.
Example fix
// before
await twitterService.deleteTweet(accessToken, userId, accountId, tweetId)
// after
try {
const freshToken = await twitterAuthService.ensureFreshToken(accountId)
await twitterService.deleteTweet(freshToken, userId, accountId, String(tweetId))
} catch (e) {
if (e.getStatus?.() === 400 && /not found/i.test(e.message)) return // already deleted
throw e
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!accessToken || !/^[0-9]+$/.test(String(tweetId))) throw new Error('invalid deleteTweet arguments') Type guard
function hasTwitterErrorDetail(e: unknown): e is { response: { data: { error: string } } } {
return typeof e === 'object' && e !== null && 'response' in e &&
typeof (e as any).response?.data?.error === 'string'
} Try / catch
try {
await twitterService.deleteTweet(accessToken, userId, accountId, tweetId)
} catch (e) {
const detail = e?.response?.data?.error || e.message
if (/401|unauthorized/i.test(detail)) await refreshTokenAndRetry()
else if (/not found/i.test(detail)) return // treat as deleted
else throw new Error(`删除推文失败: ${detail}`)
} Prevention
- Always keep tweet IDs as strings to avoid JS precision loss
- Refresh Twitter user tokens before scheduled write operations
- Request tweet.write scope at authorization time
- Treat delete of already-deleted tweets as idempotent success
When it happens
Trigger: Calling deleteTweet with an expired/revoked OAuth2 user access token (401), a tweetId that does not exist or was already deleted (404 'Not found Tweet'), or an account whose app lacks tweet.delete scope / does not own the tweet (403 'Client not allowed to access this resource' or authorization error).
Common situations: Stale tokens after user re-authorizes the app; deleting a tweet that was already removed manually; using an app-only Bearer token instead of the user context token; incorrect tweetId passed from a frontend (e.g. truncated or non-numeric id); free-tier API access lacking write endpoints.
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/154cb9e9fc4976da.
Report an issue: GitHub.