{"record":{"id":"38b8348111623ea0","repo":"yikart/AiToEarn","slug":"tiktok","errorCode":null,"errorMessage":"视频发布状态检查超时，请稍后在TikTok应用中查看发布状态","messagePattern":"视频发布状态检查超时，请稍后在TikTok应用中查看发布状态","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.service.ts","lineNumber":590,"sourceCode":"            updateTime: new Date()\n          });\n          \n          throw new BadRequestException(`视频发布失败: ${statusResult.error_message || '未知错误'}`);\n        }\n        \n        // 等待指定时间后再次查询\n        await new Promise(resolve => setTimeout(resolve, pollInterval));\n      }\n      \n      if (!finalStatus) {\n        // 超时仍未完成\n        await this.pubRecordModel.findByIdAndUpdate(pubRecord._id, {\n          status: PubStatus.FAIL,\n          failReason: '检查视频发布状态超时',\n          updateTime: new Date()\n        });\n        \n        throw new BadRequestException('视频发布状态检查超时，请稍后在TikTok应用中查看发布状态');\n      }\n      \n      // 更新发布记录为成功状态\n      const videoId = finalStatus.video_id || finalStatus.id || publish_id;\n      await this.pubRecordModel.findByIdAndUpdate(pubRecord._id, {\n        status: PubStatus.RELEASED,\n        resourceId: videoId,\n        updateTime: new Date()\n      });\n      \n      return {\n        ...finalStatus,\n        resourceId: videoId,\n        publish_id,\n      };\n    } catch (error) {\n      this.logger.error('三步式视频上传发布失败:', error.response?.data || error.message);\n      throw new BadRequestException(`视频上传发布失败: ${error.response?.data?.error?.message || error.message}`);","sourceCodeStart":572,"sourceCodeEnd":608,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.service.ts#L572-L608","documentation":"Thrown by uploadAndPublishVideo (tiktok.service.ts:590) when the polling loop exhausts maxRetries (default 30 × 2s ≈ 60s) without the status ever reaching SUCCESS/PUBLISHED or FAILED/ERROR. TikTok is still processing the video, or the status endpoint returns an unrecognized status value so the loop never matches.","triggerScenarios":"30 consecutive status polls return a non-terminal status (e.g. 'PROCESSING', 'PUBLISHING', or a different casing/wording the code doesn't recognize), so finalStatus remains null after the while loop.","commonSituations":"Large videos taking longer than ~60s to process; TikTok changing the status enum values (e.g. returning 'SENDING' or 'FINISH'); the status check succeeding but with status undefined due to response-shape drift; heavy TikTok-side processing queues.","solutions":["Increase maxRetries and/or pollInterval when calling uploadAndPublishVideo for large videos.","Log every statusResult.status value and add the unrecognized values to the terminal-status comparison.","Treat status as succeeded-if-processed by checking statusResult.data?.status when the payload is nested.","Make the failure non-fatal: since the video may still publish, return the publish_id and let the caller verify later instead of throwing.","Implement exponential backoff to cover longer processing windows without more API calls."],"exampleFix":"// before\nif (statusResult.status === 'SUCCESS' || statusResult.status === 'PUBLISHED') {\n// after\nconst ok = ['SUCCESS', 'PUBLISHED', 'SENDING', 'FINISH'];\nif (ok.includes(statusResult?.status) || statusResult?.data?.status === 'SUCCESS') {","handlingStrategy":"retry","validationCode":"null","typeGuard":"function isTerminalStatus(s: any): boolean {\n  return ['SUCCESS', 'PUBLISHED', 'FAILED', 'ERROR'].includes(String(s?.status ?? '').toUpperCase());\n}","tryCatchPattern":"try {\n  await tiktokService.uploadAndPublishVideo(token, userId, accountId, buffer, info, 3000, 60);\n} catch (e) {\n  if (e.message.includes('状态检查超时')) {\n    // publish may still complete: schedule a background job to re-check publish_id later\n    await queueStatusRecheck(accountId, publishId);\n  } else throw e;\n}","preventionTips":["Pass larger maxRetries/pollInterval for big files (e.g. 60 retries × 3s).","Never assume timeout = failure; TikTok may publish minutes later — always re-check.","Track unrecognized status strings in logs and extend the terminal-status list.","Store publish_id so late-arriving successes can be reconciled."],"tags":["tiktok","timeout","polling","async-processing"],"backgroundTag":"polling-timeout","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}