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
- 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.
- If e.retryable is true, retry with exponential backoff; otherwise surface the error to the channel sync job without retrying.
- Use exception.context.endpoint to pinpoint the failing Douyin API and verify required scopes/params for it.
- 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
- Refresh Douyin tokens proactively (refresh_token has a bounded lifetime); treat invalid-grant codes as reconnect-required, never retry.
- Throttle publishing to respect Douyin rate limits; queue posts instead of firing bursts.
- Validate client_key/client_secret and OAuth redirect URI at startup.
- Log exception.context.endpoint so failing APIs are identifiable in production.
- Health-check connectivity to open.douyin.com in the deployment environment.
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.