yikart/AiToEarn · error · BadRequestException
上传媒体失败: ${error.response?.data?.error || error.message}
Error message
上传媒体失败: ${error.response?.data?.error || error.message} What it means
uploadMedia (service) catches failures of the Twitter media upload (v1.1 media/upload) call and rethrows as BadRequestException '上传媒体失败: ...'. The detail is taken from Twitter's error payload or the axios error message. Failures typically stem from invalid media format/size or auth problems.
Source
Thrown at project/aitoearn-electron/server/src/modules/plat/twitter/twitter.service.ts:177
// 创建表单数据
const formData = new FormData();
formData.append('media', new Blob([mediaFile], { type: mimeType }));
const response = await lastValueFrom(
this.httpService.post(url, formData, {
headers: {
'Content-Type': 'multipart/form-data',
'Authorization': `Bearer ${accessToken}`
}
})
);
this.logger.log(`媒体上传成功: userId=${userId}, accountId=${accountId}`);
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 tweetId 推文ID
* @returns 删除结果
*/
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: {View on GitHub (pinned to d3aa8bea5b)
Solutions
- Read the embedded error.response?.data?.error for Twitter's specific reason (invalid media, too large, etc.).
- Validate file size and mimetype client-side against Twitter limits before uploading (images ≤5MB, GIF ≤15MB, video ≤512MB, formats PNG/JPEG/WEBP/GIF/MP4).
- For 401, re-authenticate the account to refresh the access token.
- Ensure the media category parameter matches the file type for chunked uploads (video uses tweet_video).
- Add retry for transient network errors during large video uploads.
Example fix
// before (client)
const fd = new FormData(); fd.append('file', anyFile);
// after
if (anyFile.size > 5 * 1024 * 1024 || !['image/png','image/jpeg','image/webp','image/gif'].includes(anyFile.type)) {
throw new Error('不支持的媒体格式或大小');
}
const fd = new FormData(); fd.append('file', anyFile); Defensive patterns
Strategy: validation
Validate before calling
const LIMITS = { 'image/png': 5, 'image/jpeg': 5, 'image/webp': 5, 'image/gif': 15, 'video/mp4': 512 };
const maxMB = LIMITS[file.type];
if (!maxMB || file.size > maxMB * 1024 * 1024) throw new Error('媒体格式不支持或文件过大'); Type guard
function isUploadableMedia(f: File): f is File {
return ['image/png','image/jpeg','image/webp','image/gif','video/mp4'].includes(f.type) && f.size <= 512 * 1024 * 1024;
} Try / catch
try {
await api.post('/twitter/media/upload', fd);
} catch (e) {
const msg = e.response?.data?.message || '';
if (msg.includes('上传媒体失败')) {
if (/too large|invalid media/i.test(msg)) notifyUserToCompressOrConvert();
else if (/401|Unauthorized/i.test(msg)) await reauthenticate(accountId);
}
} Prevention
- Check file size/type against Twitter media limits before upload.
- Match the media category (image/gif/video) to the file type in upload parameters.
- Use chunked upload for large videos.
- Convert unsupported formats (HEIC etc.) client-side first.
- Retry network interruptions on large uploads, resuming from the last chunk.
When it happens
Trigger: Uploading a file whose mimetype/size Twitter rejects (unsupported format, >5MB images, >512MB video), chunked upload INIT/APPEND/FINALIZE failure, expired access token, or network interruption mid-upload.
Common situations: Client uploads GIF/HEIC formats Twitter doesn't accept; oversized video without chunked upload parameters; the media category doesn't match the file type (e.g. tweet_image vs tweet_video); account token revoked between upload request and API call.
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/817c821efecbcc9d.
Report an issue: GitHub.