{"record":{"id":"5380d7c41da9c56b","repo":"yikart/AiToEarn","slug":"error-response-data-error-message-5380d7","errorCode":null,"errorMessage":"检查视频发布状态失败: ${error.response?.data?.error?.message || error.message}","messagePattern":"检查视频发布状态失败: (.+?)","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.service.ts","lineNumber":482,"sourceCode":"  ): Promise<any> {\n    try {\n      const { data } = await firstValueFrom(\n        this.httpService.post(\n          `${this.apiBaseUrl}/v2/post/publish/status/fetch/`, \n          { publish_id: publishId },\n          {\n            headers: {\n              'Content-Type': 'application/json',\n              'Authorization': `Bearer ${accessToken}`\n            }\n          }\n        )\n      );\n\n      return data.data;\n    } catch (error) {\n      this.logger.error('检查TikTok视频发布状态失败:', error.response?.data || error.message);\n      throw new BadRequestException(`检查视频发布状态失败: ${error.response?.data?.error?.message || error.message}`);\n    }\n  }\n  \n  /**\n   * 三步式完整上传并发布视频（新版API）\n   * @param accessToken 访问令牌\n   * @param userId 用户ID\n   * @param accountId TikTok账号ID\n   * @param videoBuffer 视频数据\n   * @param videoInfo 视频信息\n   * @param pollInterval 轮询状态的时间间隔（毫秒）。默认2秒。\n   * @param maxRetries 最大重试次数。默认30次，大约60秒。\n   * @returns 视频发布结果\n   */\n  async uploadAndPublishVideo(\n    accessToken: string,\n    userId: string,\n    accountId: string,","sourceCodeStart":464,"sourceCodeEnd":500,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.service.ts#L464-L500","documentation":"checkPublishStatus POSTs the publish_id to TikTok's /v2/post/publish/status/fetch/ endpoint to poll whether an uploaded video finished processing/publishing. Any HTTP or network failure from that status endpoint is caught, logged, and re-thrown as BadRequestException('检查视频发布状态失败: ...') at tiktok.service.ts:482. Note: a valid response can still contain a FAILED status — this error only fires when the request itself fails.","triggerScenarios":"Any of: invalid/expired access token (401), invalid or unknown publish_id (400), polling too early/against the wrong environment (sandbox publish_ids not queryable in production), rate limiting (429), or transient network failure during polling.","commonSituations":"Polling with a publish_id from a failed upload, polling after the upload actually failed so TikTok rejects the id, mixing .cn/.ai or sandbox/production bases, token refresh racing with a long polling loop, and hitting TikTok rate limits with tight poll intervals.","solutions":["Check the logged TikTok error body: for 401 refresh the access token; for invalid publish_id re-verify the upload actually succeeded and you are using the returned publish_id.","Ensure apiBaseUrl matches the environment that issued the token and the publish_id (sandbox vs production).","For 429 or transient errors, retry with exponential backoff instead of failing the whole poll loop.","Increase the poll interval / reduce request frequency to stay within TikTok rate limits."],"exampleFix":"// before\n} catch (error) {\n  this.logger.error('检查TikTok视频发布状态失败:', error.response?.data || error.message);\n  throw new BadRequestException(`检查视频发布状态失败: ${error.response?.data?.error?.message || error.message}`);\n}\n// after\n} catch (error) {\n  this.logger.error('检查TikTok视频发布状态失败:', error.response?.data || error.message);\n  if (error.response?.status === 429 || error.code === 'ECONNRESET' || error.code === 'ETIMEDOUT') {\n    throw new HttpException('状态查询暂时失败，可重试', HttpStatus.SERVICE_UNAVAILABLE); // caller retries\n  }\n  throw new BadRequestException(`检查视频发布状态失败: ${error.response?.data?.error?.message || error.message}`);\n}","handlingStrategy":"retry","validationCode":"if (!publishId || typeof publishId !== 'string') {\n  throw new Error('checkPublishStatus requires a non-empty publishId from a successful upload');\n}","typeGuard":"function isPublishId(v) {\n  return typeof v === 'string' && v.length > 0 && /^[A-Za-z0-9._-]+$/.test(v);\n}","tryCatchPattern":"for (let attempt = 1; attempt <= 5; attempt++) {\n  try {\n    return await checkPublishStatus(accessToken, publishId);\n  } catch (e) {\n    const transient = e.message.includes('429') || e.message.includes('500') || /timeout|ECONNRESET/i.test(e.message);\n    if (!transient || attempt === 5) throw e;\n    await new Promise(r => setTimeout(r, Math.min(2 ** attempt * 1000, 15000)));\n  }\n}","preventionTips":["Only poll with a publish_id returned from a verified-successful upload.","Use a poll interval of 2s or more and cap total retries to avoid rate limits.","Keep the status-check base URL in the same environment (sandbox/prod, cn/ai) as the upload.","Refresh the access token for long-running poll loops before it expires.","Treat repeated 'invalid publish_id' errors as an upload failure, not a polling issue."],"tags":["tiktok","publish-status","http-error","network"],"backgroundTag":"status-polling-request-failed","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}