{"record":{"id":"67fccafbbd252a71","repo":"yikart/AiToEarn","slug":"15070-67fcca","errorCode":"15070","errorMessage":"{{platform}} platform API request failed","messagePattern":"(.+?)\\} platform API request failed","errorType":"exception","errorClass":"KwaiPlatformException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/kwai/kwai.service.ts","lineNumber":41,"sourceCode":"@Injectable()\nexport class KwaiService {\n  private readonly http: AxiosInstance\n\n  constructor(private readonly cfg: KwaiConfig) {\n    this.http = this.createHttpClient()\n  }\n\n  private createHttpClient(): AxiosInstance {\n    const http = axios.create()\n    http.interceptors.response.use(\n      (response) => {\n        if (KwaiPlatformException.hasPlatformError(response)) {\n          throw KwaiPlatformException.fromPlatformResponse(response)\n        }\n        return response\n      },\n      (error: AxiosError<KwaiPlatformResponseBody>) => {\n        throw KwaiPlatformException.fromAxiosError(error)\n      },\n    )\n    return http\n  }\n\n  private async request<T>(\n    url: string,\n    config: AxiosRequestConfig = {},\n  ): Promise<KwaiApiResponse<T>> {\n    const response = await this.http.request<KwaiApiResponse<T>>({\n      ...config,\n      method: config.method ?? 'GET',\n      url,\n    })\n    return response.data\n  }\n\n  generateAuthUrl(","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/kwai/kwai.service.ts#L23-L59","documentation":"KwaiService's axios interceptor converts every failed Kwai Open API request into a KwaiPlatformException with ResponseCode.ChannelPlatformApiFailed (15070). Unlike the other services here, this interceptor also checks successful responses for a Kwai business-error payload (hasPlatformError) and throws fromPlatformResponse, but the HTTP-error branch wraps every AxiosError (network failure or non-2xx response) with fromAxiosError. The exception carries endpoint, method, HTTP status, Kwai error code/message, and retryability.","triggerScenarios":"Any request through this.http / this.request — OAuth token exchange, publishing videos, fetching account info against Kwai Open API — that fails at the network level or returns a non-2xx HTTP response; also Kwai responses whose body carries a business error even with HTTP 200 (caught by the success-branch check).","commonSituations":"Kwai access/refresh token expired; appid/appsecret misconfigured for the Kwai open platform app; publishing outside permitted quota or content policy rejection returned as a platform error code; Kwai API downtime (5xx); server unable to reach Kwai endpoints due to egress/firewall rules.","solutions":["Read the thrown KwaiPlatformException's cause (platformCode/platformMessage/httpStatus) to identify Kwai's exact error code and meaning.","If the platform code indicates token expiry, refresh the Kwai access token and retry the request.","If retryable is true (network error or 5xx), retry with backoff.","For publishing errors, validate the video URL/duration/format against Kwai's publishing requirements before retrying.","Check that the Kwai app credentials and callback domain match the open-platform console configuration, and verify network reachability to Kwai API hosts."],"exampleFix":"// before: expired token -> Kwai business error wrapped as 15070\nconst res = await this.http.post(`${this.apiBaseUrl}/openapi/photo/upload`, formData, { headers })\n\n// after: handle token expiry explicitly\ntry {\n  const res = await this.http.post(`${this.apiBaseUrl}/openapi/photo/upload`, formData, { headers })\n} catch (e) {\n  if (e instanceof KwaiPlatformException && e.cause?.platformCode === KwaiErrorCode.TokenExpired) {\n    const fresh = await this.refreshAccessToken(channel)\n    // retry with fresh token\n  } else throw e\n}","handlingStrategy":"try-catch","validationCode":"// pre-flight: credentials configured and token valid before calling Kwai Open API\nif (!cfg.appId || !cfg.appSecret) throw new Error('Kwai app credentials missing')\nif (!accessToken || tokenExpiresAt <= new Date()) await refreshKwaiToken(channel)","typeGuard":"function isKwaiPlatformException(e: unknown): e is KwaiPlatformException {\n  return e instanceof KwaiPlatformException\n}","tryCatchPattern":"try {\n  const result = await kwaiService.publishVideo(accessToken, payload)\n} catch (e) {\n  if (e instanceof KwaiPlatformException) {\n    if (e.cause?.platformCode === KwaiErrorCode.TokenExpired) {\n      // refresh token and retry once\n    } else if (e.retryable) {\n      // exponential backoff retry\n    } else {\n      // inspect cause.platformCode against Kwai docs; surface to channel owner\n    }\n  } else throw e\n}","preventionTips":["Refresh Kwai access tokens before expiry; Kwai tokens are short-lived.","Validate video URL, format, and duration against Kwai publishing requirements before uploading.","Double-check appId/appSecret and callback domain against the Kwai open-platform console.","Retry only when the exception's retryable flag is true to avoid hammering a degraded API.","Log cause.platformCode and raw body for every failure to map Kwai error codes to user actions."],"tags":["kwai","axios-interceptor","http-error","oauth","network"],"backgroundTag":"platform-api-request-failed","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}