{"record":{"id":"ed5fbb6f8828cc93","repo":"decolua/9router","slug":"failed-to-onboard-user-errortext","errorCode":null,"errorMessage":"Failed to onboard user: ${errorText}","messagePattern":"Failed to onboard user: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/lib/oauth/services/antigravity.js","lineNumber":148,"sourceCode":"      }\n    }\n\n    return { projectId, tierId, raw: data };\n  }\n\n  /**\n   * Onboard user to enable Gemini Code Assist for the project\n   */\n  async onboardUser(accessToken, projectId, tierId) {\n    const response = await fetch(this.config.onboardUserEndpoint, {\n      method: \"POST\",\n      headers: this.getApiHeaders(accessToken),\n      body: JSON.stringify({ tierId, metadata: this.getMetadata() }),\n    });\n\n    if (!response.ok) {\n      const errorText = await response.text();\n      throw new Error(`Failed to onboard user: ${errorText}`);\n    }\n\n    return await response.json();\n  }\n\n  /**\n   * Complete onboarding flow with retry\n   */\n  async completeOnboarding(accessToken, projectId, tierId, maxRetries = 10) {\n    for (let i = 0; i < maxRetries; i++) {\n      const result = await this.onboardUser(accessToken, projectId, tierId);\n\n      if (result.done === true) {\n        // Extract final project ID from response\n        let finalProjectId = projectId;\n        if (result.response?.cloudaicompanionProject) {\n          const respProject = result.response.cloudaicompanionProject;\n          if (typeof respProject === 'string') {","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/oauth/services/antigravity.js#L130-L166","documentation":"Thrown by AntigravityService.onboardUser when the POST to the Gemini Code Assist onboarding endpoint (onboardUserEndpoint) returns a non-2xx HTTP status. The raw upstream response body is embedded in the message so the underlying Google API error (quota, permission, invalid tier) is visible. It surfaces through completeOnboarding's retry loop, so it fires up to maxRetries times per connect().","triggerScenarios":"Google's onboardUser endpoint responds 4xx/5xx — e.g. invalid tierId, the GCP project lacks Cloud AI Companion API enabled, the OAuth token lacks the cloud-platform scope, or Google returns a transient 500 on every one of the 10 retries.","commonSituations":"First-time `9router` antigravity connect on a fresh Google account with no Gemini Code Assist tier; org-policy blocks the Cloud AI Companion API; expired access token mid-flow; Google-side outage during the 50-second retry window.","solutions":["Read the errorText in the message — it contains Google's actual error JSON/status; fix that root cause first","Verify the GCP project has the Gemini Code Assist / Cloud AI Companion API enabled and your account is on an allowed tier","Re-run the connect flow to obtain a fresh access token (the old one may have expired or lack scopes)","Retry later if the message shows a 5xx/rate-limit — completeOnboarding already retries 10x over ~50 seconds"],"exampleFix":"// before: raw error text only\nthrow new Error(`Failed to onboard user: ${errorText}`);\n// after: catch and add context for the user\ntry {\n  return await this.onboardUser(accessToken, projectId, tierId);\n} catch (e) {\n  throw new Error(`Onboarding failed for project ${projectId}: ${e.message}`);\n}","handlingStrategy":"try-catch","validationCode":"const res = await fetch(loadEndpoint, { method:'POST', headers: apiHeaders(token), body: JSON.stringify({ metadata }) });\nif (res.ok) { const d = await res.json(); if (!d.cloudaicompanionProject && !d.allowedTiers) console.warn('Account may not be Code Assist provisioned — onboarding will likely fail'); }","typeGuard":"function hasProjectId(r) { return r && (typeof r.cloudaicompanionProject === 'string' || (r.cloudaicompanionProject && typeof r.cloudaicompanionProject.id === 'string')); }","tryCatchPattern":"try {\n  await service.completeOnboarding(token, projectId, tierId);\n} catch (e) {\n  if (e.message.startsWith('Failed to onboard user')) {\n    // parse embedded Google error body from e.message; check API enablement/scopes before retrying\n  } else throw e;\n}","preventionTips":["Enable the Cloud AI Companion / Gemini Code Assist API on the target GCP project before connecting","Request the full required OAuth scopes (cloud-platform) during authorize","Check Google Workspace status page during suspected outages before long retry loops","Log the embedded errorText body — it contains Google's exact reason code"],"tags":["oauth","google-cloud","http-error","onboarding"],"backgroundTag":"upstream-api-error","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}