{"record":{"id":"e14df4b6c42256f0","repo":"yikart/AiToEarn","slug":"15070-e14df4","errorCode":"15070","errorMessage":"{{platform}} platform API request failed","messagePattern":"(.+?)\\} platform API request failed","errorType":"exception","errorClass":"GoogleBusinessPlatformException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/google-business/google-business.service.ts","lineNumber":28,"sourceCode":"import { GoogleBusinessPlatformException } from './google-business.exception'\nimport { GoogleBusinessOAuthGrantType } from './google-business.interface'\n\n@Injectable()\nexport class GoogleBusinessService {\n  private readonly http: AxiosInstance\n  private readonly accountApiBaseUrl = 'https://mybusinessaccountmanagement.googleapis.com/v1'\n  private readonly apiBaseUrl = 'https://mybusinessbusinessinformation.googleapis.com/v1'\n\n  constructor(private readonly cfg: GoogleBusinessConfig) {\n    this.http = this.createHttpClient()\n  }\n\n  private createHttpClient(): AxiosInstance {\n    const http = axios.create()\n    http.interceptors.response.use(\n      response => response,\n      (error: AxiosError<GoogleBusinessErrorBody>) => {\n        throw GoogleBusinessPlatformException.fromAxiosError(error)\n      },\n    )\n    return http\n  }\n\n  generateAuthUrl(scopes: string[], state: string): string {\n    const params = new URLSearchParams({\n      client_id: this.cfg.clientId,\n      redirect_uri: this.cfg.redirectUri,\n      response_type: 'code',\n      scope: scopes.join(' '),\n      state,\n      access_type: 'offline',\n      prompt: 'consent',\n    })\n\n    return `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`\n  }","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/google-business/google-business.service.ts#L10-L46","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before: token expired -> request fails with 401 wrapped in ChannelPlatformApiFailed\nconst res = await this.http.get(`${this.accountApiBaseUrl}/accounts`, { headers })\n\n// after: refresh token proactively and retry once\ntry {\n  const res = await this.http.get(`${this.accountApiBaseUrl}/accounts`, { headers })\n} catch (e) {\n  if (e instanceof GoogleBusinessPlatformException && e.cause?.httpStatus === 401) {\n    const fresh = await this.refreshAccessToken(channel)\n    const res = await this.http.get(`${this.accountApiBaseUrl}/accounts`, { headers: { Authorization: `Bearer ${fresh}` } })\n  } else throw e\n}","handlingStrategy":"try-catch","validationCode":"// before calling the API, validate config and connectivity preconditions\nif (!cfg.clientId || !cfg.clientSecret || !cfg.redirectUri) {\n  throw new Error('GoogleBusiness config incomplete: clientId/clientSecret/redirectUri required')\n}\nif (!accessToken || tokenExpiresAt <= new Date()) {\n  await refreshAccessToken(channel) // refresh before the request instead of failing\n}","typeGuard":"function isGoogleBusinessPlatformException(e: unknown): e is GoogleBusinessPlatformException {\n  return e instanceof GoogleBusinessPlatformException\n}","tryCatchPattern":"try {\n  const result = await googleBusinessService.fetchAccounts(accessToken)\n} catch (e) {\n  if (e instanceof GoogleBusinessPlatformException) {\n    if (e.retryable) {\n      // schedule retry with exponential backoff\n    } else if (e.cause?.httpStatus === 401 || e.cause?.httpStatus === 403) {\n      // trigger re-authentication / token refresh for the channel\n    } else {\n      logger.warn('Google Business API failed', { endpoint: e.context?.endpoint, message: e.cause?.platformMessage })\n    }\n  } else throw e\n}","preventionTips":["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."],"tags":["google-business-profile","axios-interceptor","http-error","oauth","network"],"backgroundTag":"platform-api-request-failed","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}