yikart/AiToEarn · error · BadRequestException
初始化视频上传失败: ${error.response?.data?.error?.message || error.m
Error message
初始化视频上传失败: ${error.response?.data?.error?.message || error.message} What it means
This BadRequestException is thrown by TikTokService.initVideoUpload when the POST to TikTok's /v2/post/publish/inbox/video/init/ endpoint fails (network/HTTP error) or returns an error payload. The service catches any axios error from firstValueFrom, logs error.response?.data, and rethrows as a NestJS BadRequestException with the TikTok API's error.message (or the axios error message) interpolated into the Chinese message '初始化视频上传失败'. It wraps the upstream TikTok Content Posting API rejection, so the inner text usually carries TikTok's own error code/message.
Source
Thrown at project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.service.ts:146
video_size: videoSize,
chunk_size: chunkSize,
total_chunk_count: totalChunkCount
};
}
const { data } = await firstValueFrom(
this.httpService.post(`${this.apiBaseUrl}/v2/post/publish/inbox/video/init/`, requestBody, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`
}
})
);
return data.data;
} catch (error) {
this.logger.error('初始化TikTok视频上传失败:', error.response?.data || error.message);
throw new BadRequestException(`初始化视频上传失败: ${error.response?.data?.error?.message || error.message}`);
}
}
/**
* 方式2:初始化视频发布(直接发布,新版)
* @param accessToken 访问令牌
* @param videoSize 视频文件总大小(字节)
* @param videoInfo 视频相关信息,包含标题、隐私级别等
* @param chunkSize 分片大小(字节),默认为10MB
* @returns 初始化结果,包含上传所需的参数
*/
async initVideoPublish(
accessToken: string,
videoSize: number,
videoInfo: {
title?: string;
description?: string;
privacyStatus?: string;View on GitHub (pinned to d3aa8bea5b)
Solutions
- Inspect this.logger.error output ('初始化TikTok视频上传失败') for error.response.data.error.code/message to get TikTok's exact error code and fix the corresponding request field.
- Verify the accessToken is valid and unexpired; if invalid_token, re-run the OAuth flow via TikTokAuthService and retry with a fresh token.
- Confirm the app's scopes include video.upload (inbox upload) and that the app passed TikTok's audit for production; sandbox apps cannot publish publicly.
- Check source_info values: video_size must equal the actual byte size of the file, chunk_size within TikTok's allowed range (e.g. >=5MB and <=64MB), total_chunk_count = ceil(video_size/chunk_size) and > 0 (videoSize is falsy for 0-byte files so source_info is omitted).
- On network-level failures (no error.response), check connectivity/proxy to open.tiktokapis.com and add timeout/retry handling in HttpService config.
Example fix
// before: error surfaced only as generic BadRequestException
throw new BadRequestException(`初始化视频上传失败: ${error.response?.data?.error?.message || error.message}`);
// after: include TikTok error code and preserve status for better diagnostics
const apiErr = error.response?.data?.error;
throw new BadRequestException(
`初始化视频上传失败: [${apiErr?.code ?? 'UNKNOWN'}] ${apiErr?.message ?? error.message}`
); Defensive patterns
Strategy: validation
Validate before calling
function assertValidInboxUploadInit(accessToken, videoSize, chunkSize = 5 * 1024 * 1024) {
if (!accessToken || typeof accessToken !== 'string') throw new Error('缺少有效的 TikTok accessToken');
if (!Number.isFinite(videoSize) || videoSize <= 0) throw new Error('videoSize 必须为正数字(字节)');
if (chunkSize < 5 * 1024 * 1024 || chunkSize > 64 * 1024 * 1024) throw new Error('chunkSize 必须在 5MB–64MB 之间');
} Type guard
function hasTikTokErrorPayload(e: unknown): e is { response: { data: { error: { code: string; message: string } } } } {
return typeof e === 'object' && e !== null &&
'response' in e && typeof (e as any).response?.data?.error?.message === 'string';
} Try / catch
try {
const initData = await tiktokService.initVideoUpload(accessToken, videoBuffer.length);
} catch (e) {
if (e instanceof BadRequestException) {
const msg = e.message;
if (msg.includes('access_token') || msg.includes('invalid')) {
// re-authenticate then retry once
} else if (msg.includes('size') || msg.includes('chunk')) {
// fix source_info values
}
}
throw e;
} Prevention
- Always compute videoSize from the actual Buffer/file (videoBuffer.length or fs.statSync().size), never a cached value.
- Keep chunkSize within TikTok's documented 5MB–64MB range.
- Refresh access tokens proactively before long upload flows and verify scopes include video.upload.
- Log error.response.data at init time so TikTok's error.code is captured for diagnosis.
- Confirm the app is production-audited; sandbox apps have restricted upload/publish behavior.
When it happens
Trigger: Any failed firstValueFrom(this.httpService.post(`${apiBaseUrl}/v2/post/publish/inbox/video/init/`, ...)) call: (1) TikTok returns 4xx/5xx (invalid/expired access_token, insufficient scopes like video.upload/video.publish, source_info invalid — e.g. video_size not matching actual file, chunk_size out of allowed range, total_chunk_count mismatch); (2) network timeout/DNS failure to open.tiktokapis.com so error.response is undefined and error.message is used; (3) response body shape unexpected causing downstream code to fail before return.
Common situations: Developers hit this when the access token was refreshed/rotated server-side but an old token is passed in, when the TikTok app lacks the video.upload or video.publish audit-approved scope (sandbox apps can only upload to private/inbox), when videoSize passed in bytes doesn't match the actual file so TikTok rejects source_info, when chunkSize is outside TikTok's allowed 5MB–64MB bounds, or when sandbox-mode apps call the production endpoint.
Related errors
- 上传视频失败: ${error.response?.data?.error?.message || error.mess
- 初始化视频发布失败: ${error.response?.data?.error?.message || error.m
- 获取视频列表失败: ${error.response?.data?.error?.message || error.me
- 获取视频详情失败: ${error.response?.data?.error?.message || error.me
- 初始化视频发布失败,缺少publish_id或upload_url
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/f2251cc5b99b2587.
Report an issue: GitHub.