yikart/AiToEarn · error · GoogleBusinessPlatformException

15070

15070

Error message

{{platform}} platform API request failed

What it means

This error is thrown by GoogleBusinessService's axios response-error interceptor, which converts every failed Google Business Profile API call into a GoogleBusinessPlatformException with ResponseCode.ChannelPlatformApiFailed (15070). It fires for both network-level Axios failures (no response at all) and non-2xx HTTP responses from mybusinessaccountmanagement / mybusinessbusinessinformation endpoints, where the platform's error body is parsed for a Google API code and message. The exception carries the endpoint, method, HTTP status, retryability, and raw platform payload as context.

Source

Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/google-business/google-business.service.ts:28

import { GoogleBusinessPlatformException } from './google-business.exception'
import { GoogleBusinessOAuthGrantType } from './google-business.interface'

@Injectable()
export class GoogleBusinessService {
  private readonly http: AxiosInstance
  private readonly accountApiBaseUrl = 'https://mybusinessaccountmanagement.googleapis.com/v1'
  private readonly apiBaseUrl = 'https://mybusinessbusinessinformation.googleapis.com/v1'

  constructor(private readonly cfg: GoogleBusinessConfig) {
    this.http = this.createHttpClient()
  }

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

  generateAuthUrl(scopes: string[], state: string): string {
    const params = new URLSearchParams({
      client_id: this.cfg.clientId,
      redirect_uri: this.cfg.redirectUri,
      response_type: 'code',
      scope: scopes.join(' '),
      state,
      access_type: 'offline',
      prompt: 'consent',
    })

    return `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`
  }

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Read exception.cause.platformMessage / httpStatus / platformCode in the thrown GoogleBusinessPlatformException to identify the concrete Google-side reason, then fix the request or credentials accordingly.
  2. If retryable is true (network error or 5xx/429), re-run the request with exponential backoff.
  3. If httpStatus is 401/403, refresh the channel's access token via exchangeCode/refresh flow and verify the Google Business Profile API is enabled for the project.
  4. If there is no response (category Network), check outbound connectivity to *.googleapis.com, proxy settings, and DNS from the server host.
  5. Verify request parameters (redirect_uri, client_id, scopes) match the Google Cloud OAuth client configuration.

Example fix

// before: token expired -> request fails with 401 wrapped in ChannelPlatformApiFailed
const res = await this.http.get(`${this.accountApiBaseUrl}/accounts`, { headers })

// after: refresh token proactively and retry once
try {
  const res = await this.http.get(`${this.accountApiBaseUrl}/accounts`, { headers })
} catch (e) {
  if (e instanceof GoogleBusinessPlatformException && e.cause?.httpStatus === 401) {
    const fresh = await this.refreshAccessToken(channel)
    const res = await this.http.get(`${this.accountApiBaseUrl}/accounts`, { headers: { Authorization: `Bearer ${fresh}` } })
  } else throw e
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before calling the API, validate config and connectivity preconditions
if (!cfg.clientId || !cfg.clientSecret || !cfg.redirectUri) {
  throw new Error('GoogleBusiness config incomplete: clientId/clientSecret/redirectUri required')
}
if (!accessToken || tokenExpiresAt <= new Date()) {
  await refreshAccessToken(channel) // refresh before the request instead of failing
}

Type guard

function isGoogleBusinessPlatformException(e: unknown): e is GoogleBusinessPlatformException {
  return e instanceof GoogleBusinessPlatformException
}

Try / catch

try {
  const result = await googleBusinessService.fetchAccounts(accessToken)
} catch (e) {
  if (e instanceof GoogleBusinessPlatformException) {
    if (e.retryable) {
      // schedule retry with exponential backoff
    } else if (e.cause?.httpStatus === 401 || e.cause?.httpStatus === 403) {
      // trigger re-authentication / token refresh for the channel
    } else {
      logger.warn('Google Business API failed', { endpoint: e.context?.endpoint, message: e.cause?.platformMessage })
    }
  } else throw e
}

Prevention

When it happens

Trigger: Any call made through this.http (exchangeCode, fetchAccounts, fetchLocations, etc.) that either fails before a response arrives (DNS failure, timeout, ECONNREFUSED, TLS error) or returns a non-2xx status from the Google Business Profile APIs (invalid OAuth code, expired/revoked access token, quota exceeded, malformed request).

Common situations: Expired or revoked Google OAuth refresh tokens; wrong redirect_uri in OAuth code exchange; Google Business Profile API not enabled on the GCP project; missing GOOGLE_APPLICATION/credentials config; network egress blocked in the deployment environment; transient Google 5xx outages.

Related errors


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