yikart/AiToEarn · error · BadRequestException
视频上传发布失败: ${error.response?.data?.error?.message || error.me
Error message
视频上传发布失败: ${error.response?.data?.error?.message || error.message} What it means
The outer catch-all of uploadAndPublishVideo (tiktok.service.ts:606-609). Any exception from the three-step flow (init, direct upload, status polling, DB writes) is re-wrapped as BadRequestException('视频上传发布失败: ...') with the deepest TikTok API error message or the original error message. It often wraps the other errors in this file (430-432), so the interesting cause is in the chained message.
Source
Thrown at project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.service.ts:608
throw new BadRequestException('视频发布状态检查超时,请稍后在TikTok应用中查看发布状态');
}
// 更新发布记录为成功状态
const videoId = finalStatus.video_id || finalStatus.id || publish_id;
await this.pubRecordModel.findByIdAndUpdate(pubRecord._id, {
status: PubStatus.RELEASED,
resourceId: videoId,
updateTime: new Date()
});
return {
...finalStatus,
resourceId: videoId,
publish_id,
};
} catch (error) {
this.logger.error('三步式视频上传发布失败:', error.response?.data || error.message);
throw new BadRequestException(`视频上传发布失败: ${error.response?.data?.error?.message || error.message}`);
}
}
/**
* 发布视频(原始方式)
* @param accessToken 访问令牌
* @param userId 用户ID
* @param accountId TikTok账号ID
* @param videoDto 视频发布参数
* @param uploadResult 上传结果,包含视频ID和初始化数据
* @returns 发布结果
*/
async publishVideo(
accessToken: string,
userId: string,
accountId: string,
videoDto: CreateVideoDto,
uploadResult: anyView on GitHub (pinned to d3aa8bea5b)
Solutions
- Check the server log line '三步式视频上传发布失败:' — it prints error.response?.data with TikTok's structured error (code, message, log_id).
- If the wrapped message is about auth, refresh the access token and ensure video.publish scope.
- If it's 429/rate-limited, back off and retry later; TikTok caps status checks and uploads per hour.
- If it's a wrapped 522/431/432 error, follow that specific error's remediation.
- Preserve the original error stack (rethrow with { cause: error }) instead of flattening to a string for easier debugging.
Example fix
// before
throw new BadRequestException(`视频上传发布失败: ${error.response?.data?.error?.message || error.message}`);
// after
throw new BadRequestException(`视频上传发布失败: ${error.response?.data?.error?.message || error.message}`, {
cause: error,
}); Defensive patterns
Strategy: try-catch
Validate before calling
// Before calling, ensure prerequisites hold:
if (!accessToken) throw new Error('missing TikTok access token');
if (!videoBuffer?.length) throw new Error('empty video buffer');
if (videoInfo.description && videoInfo.description.length > 2200) throw new Error('description too long'); Type guard
function isAxiosTikTokError(e: unknown): e is { response: { status: number; data: { error?: { code?: string; message?: string; log_id?: string } } } } {
return !!(e as any)?.response?.data;
} Try / catch
try {
return await tiktokService.uploadAndPublishVideo(token, userId, accountId, buffer, info);
} catch (e) {
const apiErr = (e as any).cause?.response?.data?.error;
logger.error('uploadAndPublish failed', { apiErr, msg: e.message });
if (apiErr?.code === 'access_token_invalid') token = await refreshTikTokToken(accountId);
throw new PublishError(e.message, { cause: (e as any).cause ?? e });
} Prevention
- Refresh tokens proactively; TikTok access tokens expire in 24h.
- Check the inner cause/origin log line, not just the generic wrapper message.
- Handle 429 with exponential backoff at the caller level.
- Log TikTok's log_id field — support can trace failures with it.
When it happens
Trigger: Any failure inside the try block: initVideoPublish/directUploadVideo/checkPublishStatus throwing AxiosErrors (4xx/5xx from TikTok), the invariant checks at lines 522/575/590 throwing, or MongoDB errors on pubRecordModel writes; error.response?.data?.error?.message is used when it's an HTTP error, error.message otherwise.
Common situations: Expired/revoked access tokens (401), missing publish scope (403), rate limiting (429), network failures during the chunked upload, Mongo connection issues, or simply seeing this generic wrapper when the real cause was error 431/432.
Related errors
- 发布视频失败: ${error.response?.data?.error?.message || error.mess
- 删除视频失败: ${error.response?.data?.error?.message || error.mess
- accountId和视频大小是必须的
- 初始化视频上传失败: ${error.response?.data?.error?.message || error.m
- 初始化响应缺少 publish_id 或 upload_url
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/dfbc4d4c5acf3a75.
Report an issue: GitHub.