{"record":{"id":"ea14b3d61cd8b11b","repo":"decolua/9router","slug":"no-cloudaicompanionproject-found-in-response","errorCode":null,"errorMessage":"No cloudaicompanionProject found in response","messagePattern":"No cloudaicompanionProject found in response","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/lib/oauth/services/antigravity.js","lineNumber":188,"sourceCode":"          }\n        }\n        return { success: true, projectId: finalProjectId };\n      }\n\n      // Wait 5 seconds before retry\n      await new Promise(resolve => setTimeout(resolve, 5000));\n    }\n\n    throw new Error(\"Onboarding timeout - please try again\");\n  }\n\n  /**\n   * Fetch Project ID from loadCodeAssist API (legacy method for compatibility)\n   */\n  async fetchProjectId(accessToken) {\n    const { projectId } = await this.loadCodeAssist(accessToken);\n    if (!projectId) {\n      throw new Error(\"No cloudaicompanionProject found in response\");\n    }\n    return projectId;\n  }\n\n  /**\n   * Save Antigravity tokens to server\n   */\n  async saveTokens(tokens, userInfo, projectId) {\n    const { server, token, userId } = getServerCredentials();\n\n    const response = await fetch(`${server}/api/cli/providers/antigravity`, {\n      method: \"POST\",\n      headers: {\n        \"Content-Type\": \"application/json\",\n        Authorization: `Bearer ${token}`,\n        \"X-User-Id\": userId,\n      },\n      body: JSON.stringify({","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/oauth/services/antigravity.js#L170-L206","documentation":"Thrown by AntigravityService.fetchProjectId when the loadCodeAssist API responded successfully but its payload contained no usable cloudaicompanionProject field (checked as a string or an {id} object after normalization in loadCodeAssist). This legacy method is a strict wrapper: a successful HTTP response without a project ID is still an error.","triggerScenarios":"loadCodeAssist returns 200 with a body lacking cloudaicompanionProject — typically when the authenticated Google account has never been provisioned a Code Assist project, or the response shape changed (field nested elsewhere / renamed).","commonSituations":"Google accounts that have never used Gemini Code Assist; GCP org accounts where the companion project lives in a different org unit; upstream API contract changes between library and Google versions.","solutions":["Call the full loadCodeAssist() and inspect its `raw` payload to see what Google actually returned","Complete the modern onboarding path (completeOnboarding) instead — it can return a newly created project ID even when loadCodeAssist has none yet","Confirm the Google account actually has Gemini Code Assist enabled on some project","Check for a library update: if Google renamed/moved the field, loadCodeAssist's extraction logic needs updating"],"exampleFix":"// before\nconst { projectId } = await this.loadCodeAssist(accessToken);\nif (!projectId) {\n  throw new Error(\"No cloudaicompanionProject found in response\");\n}\n// after: fall back to onboarding to create a project\nlet { projectId } = await this.loadCodeAssist(accessToken);\nif (!projectId) {\n  ({ projectId } = await this.completeOnboarding(accessToken, undefined, \"legacy-tier\"));\n}","handlingStrategy":"type-guard","validationCode":"const { projectId, raw } = await service.loadCodeAssist(token);\nif (!projectId) throw new Error(`loadCodeAssist returned no project. Keys: ${Object.keys(raw).join(',')}`);","typeGuard":"function hasCloudProject(data) { return data && (typeof data.cloudaicompanionProject === 'string' || (data.cloudaicompanionProject && typeof data.cloudaicompanionProject.id === 'string')); }","tryCatchPattern":"try {\n  const pid = await service.fetchProjectId(token);\n} catch (e) {\n  if (e.message.includes('cloudaicompanionProject')) {\n    // fall back to the onboarding path which can create a project\n  } else throw e;\n}","preventionTips":["Prefer the completeOnboarding flow over the legacy fetchProjectId when accounts may be unprovisioned","Inspect loadCodeAssist's `raw` return to detect upstream contract changes early","Ensure the signed-in Google account has at least one Code Assist-enabled project","Pin/update the library version when Google changes the response schema"],"tags":["oauth","google-cloud","missing-field","api-contract"],"backgroundTag":"missing-response-field","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}