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
- Read exception.cause.platformMessage / httpStatus / platformCode in the thrown GoogleBusinessPlatformException to identify the concrete Google-side reason, then fix the request or credentials accordingly.
- If retryable is true (network error or 5xx/429), re-run the request with exponential backoff.
- 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.
- If there is no response (category Network), check outbound connectivity to *.googleapis.com, proxy settings, and DNS from the server host.
- 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
- Refresh Google OAuth tokens proactively before expiry instead of waiting for 401-driven failures.
- Verify the Google Cloud project has the Business Profile APIs enabled and OAuth consent/redirect URIs configured before deploying.
- Wrap every service call in try-catch and branch on the exception's retryable/category fields rather than treating all failures alike.
- Monitor outbound connectivity to *.googleapis.com from the deployment environment.
- Log cause.platformCode and cause.raw on failures to accelerate diagnosis.
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.