yikart/AiToEarn · error · BadRequestException

分片上传视频失败: ${error.response?.data?.error?.message || error.me

Error message

分片上传视频失败: ${error.response?.data?.error?.message || error.message}

What it means

This is the catch-all wrapper for uploadVideoChunked: any failure during chunked upload of a TikTok video (network error, HTTP 4xx/5xx from the upload_url, timeout, or even the internal 'missing publish_id' BadRequestException from line 316) is logged and re-thrown as BadRequestException('分片上传视频失败: ...') at tiktok.service.ts:367. The message embeds error.response.data.error.message for Axios errors, else error.message.

Source

Thrown at project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.service.ts:367

            }
          })
        );
        
        uploadResponses.push(data);
      }
      
      // 使用最后一个分片的响应作为最终响应
      const finalResponse = uploadResponses[totalChunkCount - 1];
      
      return {
        ...finalResponse.data,
        publish_id,
        video_id: finalResponse.data?.video_id || finalResponse.data?.id,
        init_data: initData, // 返回初始化数据,可能在发布时需要
      };
    } catch (error) {
      this.logger.error('分片上传TikTok视频失败:', error.response?.data || error.message);
      throw new BadRequestException(`分片上传视频失败: ${error.response?.data?.error?.message || error.message}`);
    }
  }
  
  /**
   * 方式2:直接上传视频(PUT方式)
   * @param accessToken 访问令牌
   * @param videoBuffer 视频文件缓冲区
   * @param initData 初始化返回的数据,包含 publish_id 和 upload_url
   * @returns 上传结果
   */
  async directUploadVideo(
    accessToken: string,
    videoBuffer: Buffer,
    initData: any
  ): Promise<any> {
    try {
      const { publish_id, upload_url } = initData;
      

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Read the logged '分片上传TikTok视频失败' detail to identify which chunk and HTTP status failed; handle 401 by refreshing the access token and restarting the upload from a fresh init call.
  2. If the error indicates an expired/invalid upload_url, call initVideoUpload again to obtain a new URL and retry the full chunked upload.
  3. Add per-chunk retry with exponential backoff (chunks are idempotent per Content-Range only if TikTok supports resumable ranges — otherwise restart the upload).
  4. Verify video format/size meet TikTok requirements (mp4, within size/duration limits) before uploading.

Example fix

// before
} catch (error) {
  this.logger.error('分片上传TikTok视频失败:', error.response?.data || error.message);
  throw new BadRequestException(`分片上传视频失败: ${error.response?.data?.error?.message || error.message}`);
}
// after
} catch (error) {
  this.logger.error('分片上传TikTok视频失败:', error.response?.data || error.message);
  if (error instanceof BadRequestException) throw error; // preserve specific internal errors
  if (error.response?.status === 401) {
    throw new UnauthorizedException('TikTok 访问令牌已过期,请重新授权后重试');
  }
  throw new BadRequestException(`分片上传视频失败: ${error.response?.data?.error?.message || error.message}`);
}
Defensive patterns

Strategy: retry

Validate before calling

if (!Buffer.isBuffer(videoBuffer) || videoBuffer.length === 0) {
  throw new Error('videoBuffer must be a non-empty Buffer');
}
if (videoBuffer.length <= 10 * 1024 * 1024) {
  // skip chunked path entirely; use single-shot upload
}

Type guard

function isVideoBuffer(v) {
  return Buffer.isBuffer(v) && v.length > 0;
}

Try / catch

for (let attempt = 1; attempt <= 3; attempt++) {
  try {
    return await uploadVideo(accessToken, videoBuffer, initData);
  } catch (e) {
    if (!e.message.includes('分片上传视频失败') || attempt === 3) throw e;
    initData = await initVideoUpload(accessToken, videoBuffer.length); // fresh URL
    await new Promise(r => setTimeout(r, 2 ** attempt * 1000));
  }
}

Prevention

When it happens

Trigger: Any of: one of the 5MB chunk POSTs to upload_url returns a non-2xx status; the upload_url has expired (TikTok upload URLs are time-limited); Content-Range/Content-Length headers rejected; network interruption mid-upload; or the internal missing publish_id/upload_url throw bubbling into this catch.

Common situations: Videos where upload takes longer than TikTok's URL TTL, expired or revoked access tokens (401 from TikTok), file exceeding TikTok size/format limits mid-way, transient network failures on large multi-chunk uploads, and retrying after the URL already consumed.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/cebb06d773d2e02b. Report an issue: GitHub.