yikart/AiToEarn · error · BilibiliPlatformException

15070

15070

Error message

{{platform}} platform API request failed

What it means

BilibiliService builds its Axios instance in createPlatformHttpClient with response interceptors that normalize every failure into a BilibiliPlatformException (a ChannelPlatformException) whose user-facing template is '{{platform}} platform API request failed' (code 15070). fromAxiosError fires for network-level failures (timeout, DNS, connection refused) and HTTP error statuses on calls to Bilibili open APIs; fromPlatformResponse fires when Bilibili returns HTTP 200 but a body code other than 0. The exception carries httpStatus, platformCode, endpoint context, a retryable flag, and a category so callers can classify it.

Source

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

    private readonly mediaService: MediaService,
  ) {
    this.platformHttp = this.createPlatformHttpClient()
  }

  private readonly authPageUrl = 'https://account.bilibili.com/pc/account-pc/auth/oauth'
  private readonly openBaseUrl = 'https://member.bilibili.com'

  private createPlatformHttpClient(): AxiosInstance {
    const http = axios.create()
    http.interceptors.response.use(
      (response) => {
        if (BilibiliPlatformException.hasPlatformError(response)) {
          throw BilibiliPlatformException.fromPlatformResponse(response)
        }
        return response
      },
      (error: AxiosError<BilibiliPlatformResponseBody>) => {
        throw BilibiliPlatformException.fromAxiosError(error)
      },
    )
    return http
  }

  generateAuthUrl(state: string): string {
    const params = new URLSearchParams({
      client_id: this.cfg.clientId,
      gourl: this.cfg.redirectUri,
      state,
    })

    return `${this.authPageUrl}?${params.toString()}`
  }

  async exchangeCode(code: string): Promise<{
    accessToken: string
    refreshToken: string

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Read exception.cause.httpStatus and cause.platformCode: 401/-101 style codes mean reconnect the Bilibili account (refresh tokens via the channel service) rather than retrying.
  2. If retryable is true (5xx per isHttpStatusRetryable, or no response = network error), retry the request with backoff.
  3. Check the endpoint in exception.context to identify which Bilibili API failed and verify app credentials/env config for that endpoint.
  4. Confirm outbound network access (proxy, DNS, firewall) from the server to the Bilibili open API; reproduce with curl from the same container.

Example fix

// before: treating every platform failure the same
try {
  await bilibiliService.publish(account, payload)
} catch (e) {
  this.logger.error('publish failed')
}

// after: branch on the classified ChannelPlatformException
try {
  await bilibiliService.publish(account, payload)
} catch (e) {
  if (e instanceof ChannelPlatformException) {
    if (e.retryable) return this.retryWithBackoff(e)
    if (e.cause?.httpStatus === 401) return this.markAccountReauthRequired(account)
  }
  throw e
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before calling: fail fast on missing credentials and check account token presence
if (!config.bilibiliAppKey || !config.bilibiliAppSecret) {
  throw new Error('BILIBILI app credentials are not configured')
}
if (!account.accessToken) {
  throw new Error(`Bilibili account ${account.id} has no access token; reconnect required`)
}

Type guard

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

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

Try / catch

try {
  return await bilibiliService.publish(account, payload)
} catch (e) {
  if (isBilibiliPlatformError(e)) {
    if (e.retryable) return retryWithBackoff(e)
    if (e.cause.httpStatus === 401) return markAccountNeedsReauth(account.id)
  }
  throw e
}

Prevention

When it happens

Trigger: Any axios request through this client whose promise rejects (network error, timeout, 4xx/5xx status), or where Bilibili responds with a non-zero body `code` (e.g. -101 invalid access_token, -352 risk control); typical call sites are OAuth token exchange, auth-url flows, and content publishing via the interceptor-wrapped http instance.

Common situations: Expired or revoked Bilibili access tokens bound to the connected account; Bilibili API downtime or 5xx during publishes; hitting Bilibili rate limits/risk control (-352, -412); misconfigured Bilibili app credentials causing 4xx on token endpoints; container DNS/proxy issues blocking outbound calls.

Related errors


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