yikart/AiToEarn · error · TwitterPlatformException

15070

15070

Error message

{{platform}} platform API request failed

What it means

TwitterService.createOAuthHttpClient() builds a bare Axios instance for Twitter OAuth endpoints (token exchange/refresh at api.x.com / twitter.com). Its response interceptor converts any AxiosError carrying a TwitterOAuthErrorBody ({error, error_description}) into TwitterPlatformException with code ChannelPlatformApiFailed (15070). This surfaces OAuth-level failures such as invalid client credentials, bad grant, or invalid redirect URI.

Source

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

import { TwitterPlatformException, TwitterWorkLinkException, TwitterWorkNotFoundException } from './twitter.exception'

@Injectable()
export class TwitterService {
  private readonly logger = new Logger(TwitterService.name)
  private readonly oauthHttp: AxiosInstance

  constructor(
    private readonly cfg: TwitterConfig,
  ) {
    this.oauthHttp = this.createOAuthHttpClient()
  }

  private createOAuthHttpClient(): AxiosInstance {
    const http = axios.create()
    http.interceptors.response.use(
      response => response,
      (error: AxiosError<TwitterOAuthErrorBody>) => {
        throw TwitterPlatformException.fromAxiosError(error)
      },
    )
    return http
  }

  private createOAuth2Client(scopes?: string[]) {
    return new OAuth2({
      clientId: this.cfg.clientId,
      clientSecret: this.cfg.clientSecret || undefined,
      redirectUri: this.cfg.redirectUri,
      scope: scopes,
    })
  }

  private createApiClient(accessToken: string): Client {
    return new Client({
      accessToken,
      headers: { 'Content-Type': 'application/json' },

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Compare exception.cause (error, error_description) with Twitter OAuth error values (invalid_grant, invalid_client, unauthorized_client)
  2. If invalid_grant: the auth code was used/expired — restart the OAuth flow with a fresh state
  3. Verify client_id/client_secret and redirect_uri exactly match the X developer portal app settings
  4. For refresh failures, mark the channel disconnected and prompt the user to re-authorize
  5. Check network access to the Twitter OAuth host if no HTTP status was returned

Example fix

// before
const token = await twitterService.exchangeCode(code) // throws 15070 on invalid_grant
// after
try {
  const token = await twitterService.exchangeCode(code)
} catch (e) {
  if (e instanceof ChannelPlatformException && e.cause?.platformMessage?.includes('invalid_grant')) {
    // code expired/used — redirect user to twitterService.generateAuthUrl(...) again
  }
  throw e
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!clientId || !clientSecret || !redirectUri) throw new Error('Twitter OAuth credentials/redirect_uri are not configured')
// also: use the code immediately — authorization codes are single-use and short-lived

Type guard

function isTwitterPlatformException(e: unknown): e is TwitterPlatformException {
  return e instanceof TwitterPlatformException
}

Try / catch

try {
  const token = await twitterService.exchangeCode(code)
} catch (e) {
  if (e instanceof ChannelPlatformException) {
    const desc = e.cause?.platformMessage ?? ''
    if (desc.includes('invalid_grant')) return restartOAuthFlow() // code expired/used
    if (desc.includes('invalid_client')) logger.error('Check TWITTER_CLIENT_ID/SECRET and redirect_uri')
  }
  throw e
}

Prevention

When it happens

Trigger: OAuth token requests fail: invalid or expired authorization code, mismatched client_id/client_secret, redirect_uri not matching the registered callback, unsupported grant_type, expired/revoked refresh token, or network failure reaching the Twitter OAuth endpoint.

Common situations: User takes too long between authorization and code exchange (code expires ~30s-30min); wrong callback URL registered in the X developer portal; X API credentials rotated or app suspended; environment misconfig between production/staging callback URLs; refresh token revoked by user.

Related errors


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