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 in directUploadVideo: any failure while PUT-ing the video (single-shot or 10MB chunks) to TikTok's upload_url — HTTP errors, expired URL, token rejection, network failure — is logged and re-thrown as BadRequestException('直接上传视频失败: ...') at tiktok.service.ts:451. The embedded detail comes from error.response.data.error.message (Axios) or error.message.

Source

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

                'Content-Type': contentType,
                'Content-Length': chunkLength.toString(),
                'Content-Range': `bytes ${start}-${end-1}/${totalSize}`,
                'Authorization': `Bearer ${accessToken}`
              }
            })
          );
          
          lastResponse = data;
        }
        
        return {
          publish_id,
          ...lastResponse?.data,
        };
      }
    } catch (error) {
      this.logger.error('直接上传TikTok视频失败:', error.response?.data || error.message);
      throw new BadRequestException(`直接上传视频失败: ${error.response?.data?.error?.message || error.message}`);
    }
  }
  
  /**
   * 检查视频发布状态
   * @param accessToken 访问令牌
   * @param publishId 发布ID
   * @returns 发布状态信息
   */
  async checkPublishStatus(
    accessToken: string,
    publishId: string
  ): Promise<any> {
    try {
      const { data } = await firstValueFrom(
        this.httpService.post(
          `${this.apiBaseUrl}/v2/post/publish/status/fetch/`, 
          { publish_id: publishId },

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Inspect the logged '直接上传TikTok视频失败' body for TikTok's error code; on auth errors re-authorize and restart from the init step.
  2. Re-run the init call to get a fresh upload_url if the error suggests an expired/invalid URL, then retry.
  3. Confirm the file is mp4 and within TikTok size limits; convert/transcode if not.
  4. Add retry-with-backoff for transient network errors (5xx/timeouts) around each PUT, and avoid re-wrapping internal BadRequestExceptions so root causes stay visible.

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;
  throw new BadRequestException(`直接上传视频失败: ${error.response?.data?.error?.message || error.message}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!initData?.upload_url) throw new Error('missing upload_url');
const MAX = 2 * 1024 * 1024 * 1024; // check TikTok's documented limit
if (videoBuffer.length > MAX) throw new Error('video exceeds TikTok size limit');
if (!videoBuffer.slice(0, 12).toString('latin1').includes('ftyp')) {
  this.logger.warn('videoBuffer may not be a valid MP4');
}

Type guard

function isMp4Buffer(v) {
  return Buffer.isBuffer(v) && v.length > 11
    && v.readUInt32BE(4) === 0x66747970; // 'ftyp' box
}

Try / catch

try {
  const result = await directUploadVideo(accessToken, videoBuffer, initData);
} catch (e) {
  const detail = /直接上传视频失败: (.*)/.exec(e.message)?.[1] ?? e.message;
  if (detail.includes('401') || detail.toLowerCase().includes('unauthorized')) {
    // refresh token then re-init and retry
  } else if (/expired|invalid.*url/i.test(detail)) {
    // re-init for a fresh upload_url
  } else throw e;
}

Prevention

When it happens

Trigger: Any of: the PUT to upload_url returns 4xx/5xx (expired signature, invalid token, wrong content type), a >10MB video's Content-Range chunk is rejected, connection reset mid-PUT, or the internal missing-field throw from line 387 being re-caught here and re-wrapped.

Common situations: Upload URL TTL expired while preparing a large file, access token expired or wrong environment, TikTok rejecting non-mp4 or oversized files, unstable network on large uploads, and double-wrapping masking the original root cause.

Related errors


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