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: any

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Check the server log line '三步式视频上传发布失败:' — it prints error.response?.data with TikTok's structured error (code, message, log_id).
  2. If the wrapped message is about auth, refresh the access token and ensure video.publish scope.
  3. If it's 429/rate-limited, back off and retry later; TikTok caps status checks and uploads per hour.
  4. If it's a wrapped 522/431/432 error, follow that specific error's remediation.
  5. 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

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


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