{"record":{"id":"c3f730b95a9494ad","repo":"yikart/AiToEarn","slug":"channelplatformapifailed-c3f730","errorCode":"ChannelPlatformApiFailed","errorMessage":"ChannelPlatformApiFailed","messagePattern":"ChannelPlatformApiFailed","errorType":"error_code","errorClass":"AppException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/douyin/douyin.service.ts","lineNumber":244,"sourceCode":"      openId: user.open_id,\n      unionId: user.union_id,\n      nickname: user.nickname,\n      avatar: user.avatar,\n      city: user.city,\n      province: user.province,\n      country: user.country,\n      eAccountRole: user.e_account_role,\n    }\n  }\n\n  async getShareid(): Promise<string> {\n    const response = await this.requestShareId<DouyinShareIdEnvelope>({\n      need_callback: true,\n      default_hashtag: 'hashtag',\n    })\n    const shareId = response.data.data?.share_id\n    if (!shareId) {\n      throw new AppException(ResponseCode.ChannelPlatformApiFailed, { platform: AccountType.Douyin, field: 'share_id', reasonCode: 'missing_platform_field' })\n    }\n\n    return shareId\n  }\n\n  async getSharePublishResult(shareId: string): Promise<DouyinSharePublishResult> {\n    const response = await this.requestShareId<DouyinSharePublishResultEnvelope>({\n      share_id: shareId,\n    })\n    const data = response.data.data ?? {}\n\n    return {\n      shareId: data.share_id ?? shareId,\n      itemId: data.item_id,\n      videoId: data.video_id,\n      shareUrl: data.share_url,\n      raw: data,\n    }","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/douyin/douyin.service.ts#L226-L262","documentation":"ChannelPlatformApiFailed (field share_id) is thrown by DouyinService.getShareid when the /share-id/ call to the Douyin Open Platform succeeds at HTTP level but response.data.data.share_id is missing or empty. It signals that the platform responded unexpectedly rather than a transport error, and the service carries reasonCode 'missing_platform_field' to pinpoint which field was absent.","triggerScenarios":"Any call path that requests a Douyin share id (offline-QR publish handoff) where the /share-id/ envelope returns data=null, an error payload (e.g. client_token invalid, app quota exceeded, wrong client_key), or a data object without share_id.","commonSituations":"Douyin Open Platform app credentials (clientId/clientSecret) misconfigured; app not approved for share-id API; Douyin returning an error envelope that the HTTP layer does not reject; platform-side incidents; request signature/token mismatch after credential rotation.","solutions":["Inspect the raw response body from POST https://open.douyin.com/share-id/ to see the platform error code/message returned in the envelope.","Verify DOUYIN client_key/client_secret config matches an approved Douyin Open Platform app with share permissions.","Confirm the client token used is valid (this path refreshes stale tokens, but a hard credential failure still yields an empty share_id).","Retry after confirming Douyin platform status; if quota-limited, reduce share-id request rate or request a quota increase."],"exampleFix":"// before\n// response: { data: { data: null, description: 'client_key invalid' } } -> throws\nconst shareId = await douyinService.getShareid()\n// after\n// fix config so the envelope contains data.share_id\n// DOUYIN_CLIENT_KEY=<approved key>; DOUYIN_CLIENT_SECRET=<matching secret>\nconst shareId = await douyinService.getShareid() // returns e.g. 'share_abc123'","handlingStrategy":"retry","validationCode":null,"typeGuard":"const hasShareId = (r: unknown): r is { data: { data: { share_id: string } } } =>\n  !!r && typeof r === 'object' &&\n  !!(r as any).data?.data?.share_id","tryCatchPattern":"try {\n  const shareId = await douyinService.getShareid()\n} catch (err) {\n  if (err instanceof AppException && err.code === ResponseCode.ChannelPlatformApiFailed && err.data?.field === 'share_id') {\n    // check Douyin platform error envelope / credentials, then retry with backoff\n  } else throw err\n}","preventionTips":["Keep Douyin Open Platform clientId/clientSecret config verified in every environment","Monitor platform error codes returned in the /share-id/ envelope, not just HTTP status","Apply backoff between share-id requests to avoid quota limits","Subscribe to Douyin Open Platform status/announcements for API changes"],"tags":["douyin","third-party-api","missing-field","open-platform"],"backgroundTag":"missing-platform-field","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}