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
- Compare exception.cause (error, error_description) with Twitter OAuth error values (invalid_grant, invalid_client, unauthorized_client)
- If invalid_grant: the auth code was used/expired — restart the OAuth flow with a fresh state
- Verify client_id/client_secret and redirect_uri exactly match the X developer portal app settings
- For refresh failures, mark the channel disconnected and prompt the user to re-authorize
- 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
- Exchange authorization codes immediately; never reuse a code
- Ensure the redirect_uri matches the X developer portal app exactly, including scheme and trailing slash
- Distinguish OAuth errors via cause.platformMessage (error_description) for targeted handling
- Detect refresh-token revocation and mark the channel as needing re-authorization
- Keep separate credentials per environment and never mix staging callbacks with production apps
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.