{"record":{"id":"729aa79749f15395","repo":"yikart/AiToEarn","slug":"accountid-publishid","errorCode":null,"errorMessage":"accountId和publishId是必须的","messagePattern":"accountId和publishId是必须的","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.controller.ts","lineNumber":464,"sourceCode":"  @Post('videos/publish/status')\n  @ApiOperation({ summary: '检查视频发布状态' })\n  @ApiBody({\n    schema: {\n      type: 'object',\n      properties: {\n        accountId: { type: 'string', description: 'TikTok账号ID' },\n        publishId: { type: 'string', description: '发布ID' }\n      },\n      required: ['accountId', 'publishId']\n    }\n  })\n  async checkPublishStatus(\n    @GetToken() systemToken: TokenInfo,\n    @Body('accountId') accountId: string,\n    @Body('publishId') publishId: string\n  ) {\n    if (!accountId || !publishId) {\n      throw new BadRequestException('accountId和publishId是必须的');\n    }\n\n    const accessToken = await this.tikTokAuthService.getUserAccessToken(accountId);\n    return this.tikTokService.checkPublishStatus(accessToken, publishId);\n  }\n\n  /**\n   * 一键上传并发布视频（新版API三步法）\n   */\n  @Post('videos/publish')\n  @ApiOperation({ summary: '一键上传并发布视频（新版API）' })\n  @ApiConsumes('multipart/form-data')\n  @ApiBody({\n    schema: {\n      type: 'object',\n      properties: {\n        accountId: { type: 'string', description: 'TikTok账号ID' },\n        title: { type: 'string', description: '视频标题' },","sourceCodeStart":446,"sourceCodeEnd":482,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.controller.ts#L446-L482","documentation":"checkPublishStatus needs both accountId (to resolve the account's access token) and publishId (the publish job ID returned by the upload/init flow) in the request body. Missing either yields this 400 BadRequestException. The publishId comes from a previous uploadAndPublishVideo/init step, so this error often means that earlier response was dropped.","triggerScenarios":"Polling publish status before storing the publishId from the init/upload response, or calling without accountId.","commonSituations":"Status-poller jobs restarted after process restart losing the publishId; race where polling starts before the init call returns; accountId not persisted with the publish job.","solutions":["Persist the publishId returned by the upload/init step and send it in every status check.","Include accountId alongside publishId in the body.","Only start polling after the publish-init call has successfully returned a publishId."],"exampleFix":"// before\nawait api.post('/tiktok/video/publish/status', { accountId });\n// after\nawait api.post('/tiktok/video/publish/status', { accountId, publishId });","handlingStrategy":"validation","validationCode":"if (!publishJob?.accountId || !publishJob?.publishId) {\n  throw new Error('Cannot check status: publishId must be stored from the init/upload response');\n}","typeGuard":"function isPublishJob(j: { accountId?: string; publishId?: string }): j is { accountId: string; publishId: string } {\n  return typeof j.accountId === 'string' && j.accountId !== '' &&\n         typeof j.publishId === 'string' && j.publishId !== '';\n}","tryCatchPattern":"try {\n  const status = await api.post('/tiktok/video/publish/status', publishJob);\n} catch (e) {\n  if (e.response?.status === 400) {\n    stopPolling();\n    console.error('Missing accountId/publishId — publish job state lost');\n  }\n}","preventionTips":["Persist publishId (DB/localStorage) immediately after the init/upload response.","Only start status polling once a valid publishId is stored.","Bundle accountId and publishId in one PublishJob type passed to the poller."],"tags":["bad-request","validation","tiktok","missing-parameter","publish"],"backgroundTag":"missing-required-parameter","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}