{"record":{"id":"28471b09bc08d06b","repo":"yikart/AiToEarn","slug":"channelplatformapifailed","errorCode":"ChannelPlatformApiFailed","errorMessage":"ResponseCode.ChannelPlatformApiFailed","messagePattern":"ResponseCode\\.ChannelPlatformApiFailed","errorType":"exception","errorClass":"AppException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/douyin/douyin-miniapp.service.ts","lineNumber":76,"sourceCode":"    const response = await this.http.post<DouyinMiniAppQrCodeResponse>(\n      this.endpoints.qrCode,\n      {\n        app_name: options.appName,\n        appid: miniApp.clientId,\n        path: options.path,\n        width: options.width,\n        is_circle_code: options.isCircleCode,\n      },\n      {\n        headers: {\n          'Content-Type': 'application/json',\n          'access-token': accessToken,\n        },\n      },\n    )\n    const img = response.data.data?.img\n    if (!img) {\n      throw new AppException(ResponseCode.ChannelPlatformApiFailed, { platform: AccountType.Douyin, field: 'img', reasonCode: 'missing_platform_field' })\n    }\n\n    return img\n  }\n\n  async code2Session(code: string): Promise<DouyinMiniAppSessionInfo> {\n    const miniApp = this.miniAppConfig\n    const response = await this.http.post<DouyinMiniAppCode2SessionResponse>(\n      this.endpoints.code2Session,\n      {\n        appid: miniApp.clientId,\n        secret: miniApp.clientSecret,\n        code,\n      },\n      {\n        headers: {\n          'Content-Type': 'application/json',\n        },","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/douyin/douyin-miniapp.service.ts#L58-L94","documentation":"createQrCode calls Douyin's mini-app QR-code HTTP API and throws ChannelPlatformApiFailed when the response succeeds but data.data.img is missing. It represents an upstream Douyin API response that lacks the expected image field.","triggerScenarios":"Calling createQrCode with a valid accessToken when Douyin returns a 200 whose body has no data.img (e.g. Douyin-side error payload, rate limit encoded in body, or invalid request params Douyin silently ignores).","commonSituations":"Douyin API partial outage, mini-app QR generation quota exceeded, wrong scene/content params, or accessToken valid but lacking permission for QR generation.","solutions":["Log the full Douyin response body to see any embedded error code before the img check","Verify the QR generation request params and accessToken permissions against the Douyin docs","Retry after backoff if it's transient; otherwise check the Douyin open-platform console for quota/permission issues"],"exampleFix":"// before\nconst img = response.data.data?.img\nif (!img) {\n  throw new AppException(ResponseCode.ChannelPlatformApiFailed, { platform: AccountType.Douyin, field: 'img', reasonCode: 'missing_platform_field' })\n}\n// after\nconst img = response.data.data?.img\nif (!img) {\n  this.logger.warn(`douyin qr response: ${JSON.stringify(response.data)}`)\n  throw new AppException(ResponseCode.ChannelPlatformApiFailed, { platform: AccountType.Douyin, field: 'img', reasonCode: 'missing_platform_field', body: response.data })\n}","handlingStrategy":"retry","validationCode":"if (!accessToken || accessToken.length === 0) {\n  throw new Error('Cannot create Douyin QR code without an access token')\n}","typeGuard":"function hasQrImage(res: { data?: { data?: { img?: unknown } } }): res is { data: { data: { img: string } } } {\n  return typeof res.data?.data?.img === 'string' && res.data.data.img.length > 0\n}","tryCatchPattern":"try {\n  const img = await service.createQrCode(accessToken, params)\n} catch (e) {\n  if (e instanceof AppException && e.code === 'ChannelPlatformApiFailed') {\n    logger.warn('douyin qr response missing img; inspecting upstream body', { detail: e.details })\n    // backoff and retry, or fall back to another QR source\n  } else throw e\n}","preventionTips":["Log the full upstream response body whenever an expected field is missing","Refresh the access token before QR generation if it is near expiry","Add retries with exponential backoff for transient Douyin API issues","Monitor Douyin status/quota for the mini-app"],"tags":["douyin","api","third-party","http"],"backgroundTag":"upstream-api-missing-field","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}