yikart/AiToEarn · error · DouyinPlatformException

15070

15070

Error message

{{platform}} platform API request failed

What it means

DouyinService's createHttpClient wraps its Axios instance with the same interceptor pair as the mini-app service: every rejection goes through DouyinPlatformException.fromAxiosError and every 200-with-error-code body through fromPlatformResponse, producing a ChannelPlatformException with message '{{platform}} platform API request failed' (code 15070). It applies to the main Douyin open-platform APIs (OAuth, video publishing, account info). The exception preserves the HTTP status, Douyin platform code, endpoint, and a retryable/category classification.

Source

Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/douyin/douyin.service.ts:68

  constructor(
    private readonly cfg: DouyinConfig,
    private readonly redis: ServerRedisService,
  ) {
    this.http = this.createHttpClient()
  }

  private createHttpClient(): AxiosInstance {
    const http = axios.create({ baseURL: this.apiBaseUrl })
    http.interceptors.response.use(
      (response) => {
        if (DouyinPlatformException.hasPlatformError(response)) {
          throw DouyinPlatformException.fromPlatformResponse(response)
        }
        return response
      },
      (error: AxiosError<DouyinPlatformResponseBody>) => {
        throw DouyinPlatformException.fromAxiosError(error)
      },
    )
    return http
  }

  private async apiRequest<T>(
    method: 'GET' | 'POST',
    path: string,
    params: Record<string, string> = {},
    body?: DouyinApiRequestBody,
    accessToken?: string,
  ): Promise<T> {
    const headers = {
      ...(accessToken ? { 'access-token': accessToken } : {}),
      ...(body ? { 'Content-Type': 'application/json' } : {}),
    }

    const response = await this.http.request<DouyinApiResponse<T>>({

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Check exception.cause.platformCode / httpStatus: auth codes mean re-run the Douyin OAuth connect flow for the account; rate-limit codes mean back off before retrying.
  2. If e.retryable is true, retry with exponential backoff; otherwise surface the error to the channel sync job without retrying.
  3. Use exception.context.endpoint to pinpoint the failing Douyin API and verify required scopes/params for it.
  4. Validate client_key/client_secret and callback URL configuration; confirm outbound access to open.douyin.com from the deployment environment.

Example fix

// before: treating token expiry as transient
catch (e) {
  await this.queue.retry(job)
}

// after: force reconnect on auth failures, retry only when retryable
catch (e) {
  if (e instanceof ChannelPlatformException) {
    if (e.cause?.httpStatus === 401) {
      await this.channels.markNeedsReauth(account)
      return
    }
    if (e.retryable) return this.queue.retry(job)
  }
  throw e
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: ensure an account is authorized before publishing jobs
if (!account.douyinRefreshToken || account.douyinTokenExpiresAt < Date.now() + 60_000) {
  await refreshDouyinToken(account) // throws classified ChannelPlatformException early
}

Type guard

import { ChannelPlatformException } from '../channels/platforms/platforms.exception'

function isDouyinPlatformError(e: unknown): e is ChannelPlatformException {
  return e instanceof ChannelPlatformException
    && e.platform === 'douyin'
    && (e.cause?.platformCode !== undefined || typeof e.cause?.httpStatus === 'number')
}

Try / catch

try {
  return await douyinService.publish(account, post)
} catch (e) {
  if (isDouyinPlatformError(e)) {
    if (e.cause?.httpStatus === 401) {
      return markAccountNeedsReauth(account.id)
    }
    if (e.retryable) return retryWithBackoff(e)
  }
  throw e
}

Prevention

When it happens

Trigger: OAuth token refresh/exchange calls with invalid or expired refresh_token; publishing/upload endpoints returning non-zero error_code (e.g. invalid access_token, rate-limit codes); 4xx/5xx HTTP responses from open.douyin.com; network-level axios rejections (timeout, connection refused, DNS).

Common situations: Douyin account authorization revoked or expired so refresh fails with invalid grant; Douyin API rate limits during bulk publishing; misconfigured DOUYIN client_key/client_secret in env; Douyin-side 5xx incidents; corporate proxy blocking outbound HTTPS to open.douyin.com.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/01ca4fa5adf120a2. Report an issue: GitHub.