{"record":{"id":"5e50f435a0c270cc","repo":"decolua/9router","slug":"failed-to-load-code-assist-errortext","errorCode":null,"errorMessage":"Failed to load code assist: ${errorText}","messagePattern":"Failed to load code assist: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/lib/oauth/services/antigravity.js","lineNumber":111,"sourceCode":"   * Uses numeric enum values matching Antigravity binary ClientMetadata.\n   */\n  getMetadata() {\n    return getOAuthClientMetadata();\n  }\n\n  /**\n   * Fetch Project ID and Tier from loadCodeAssist API\n   */\n  async loadCodeAssist(accessToken) {\n    const response = await fetch(this.config.loadCodeAssistEndpoint, {\n      method: \"POST\",\n      headers: this.getApiHeaders(accessToken),\n      body: JSON.stringify({ metadata: this.getMetadata() }),\n    });\n\n    if (!response.ok) {\n      const errorText = await response.text();\n      throw new Error(`Failed to load code assist: ${errorText}`);\n    }\n\n    const data = await response.json();\n\n    // Extract project ID\n    let projectId = data.cloudaicompanionProject;\n    if (typeof projectId === 'object' && projectId !== null && projectId.id) {\n      projectId = projectId.id;\n    }\n\n    // Extract tier ID (default to legacy-tier)\n    let tierId = \"legacy-tier\";\n    if (Array.isArray(data.allowedTiers)) {\n      for (const tier of data.allowedTiers) {\n        if (tier.isDefault && tier.id) {\n          tierId = tier.id.trim();\n          break;\n        }","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/oauth/services/antigravity.js#L93-L129","documentation":"AntigravityService.loadCodeAssist POSTs to the cloudaicompanion loadCodeAssist endpoint with client metadata and throws this on non-2xx, embedding the response body. This call resolves the user's Cloud project ID and tier, so failing here blocks the whole Antigravity onboarding.","triggerScenarios":"Access token expired or lacking required Gemini Code Assist scopes (401/403); the user's Google account has no Code Assist/Gemini project provisioned; loadCodeAssist endpoint URL outdated after a Google-side change; the required loadCodeAssistUserAgent is rejected; 429 quota throttling.","commonSituations":"Calling loadCodeAssist long after token exchange without refresh; the Antigravity endpoint moved after an upstream update (common with reverse-engineered APIs); the account is not yet onboarded and needs onboardUser first; region not supported.","solutions":["Refresh the access token and retry — 401 means the bearer token expired","Inspect the embedded body: 403 usually means scopes/entitlement; 404 means the endpoint moved","Update ANTIGRAVITY_CONFIG.loadCodeAssistEndpoint to the current Antigravity API URL","Ensure getApiHeaders sends the exact loadCodeAssistUserAgent Antigravity expects","If the project is not yet provisioned, follow up with the onboardUser flow"],"exampleFix":"// before\nconst { projectId } = await svc.loadCodeAssist(staleAccessToken);\n// after\nconst fresh = await refreshAccessToken(refreshToken); // 401 protection\nlet res;\ntry { res = await svc.loadCodeAssist(fresh); }\ncatch (e) {\n  if (/ 404|Not Found/.test(e.message)) throw new Error('loadCodeAssist endpoint changed — update ANTIGRAVITY_CONFIG');\n  throw e;\n}","handlingStrategy":"retry","validationCode":"// pre-flight: fresh token\nconst freshToken = await ensureFreshAccessToken(); // refresh if >55min old\nif (!freshToken) throw new Error('No valid Antigravity token — re-run OAuth before loadCodeAssist');","typeGuard":"const isCodeAssistError = (e) => e instanceof Error && e.message.startsWith('Failed to load code assist:');\nconst classify = (e) => /\\b401\\b/.test(e.message) ? 'token-expired'\n  : /\\b403\\b/.test(e.message) ? 'no-entitlement'\n  : /\\b404\\b/.test(e.message) ? 'endpoint-moved'\n  : /\\b429\\b/.test(e.message) ? 'throttled' : 'server-error';","tryCatchPattern":"try { const { projectId, tierId } = await svc.loadCodeAssist(token); }\ncatch (e) {\n  if (!isCodeAssistError(e)) throw e;\n  const kind = classify(e);\n  if (kind === 'token-expired') retryWithRefreshedToken();\n  else if (kind === 'throttled') await sleep(5000).then(retry);\n  else throw new Error(`loadCodeAssist ${kind} — ${e.message.slice(0, 120)}`);\n}","preventionTips":["Always refresh the access token before loadCodeAssist if the exchange was >~1h ago","Monitor the Antigravity endpoint URL — reverse-engineered Google APIs move often","Send the exact loadCodeAssistUserAgent the client expects","Handle the not-provisioned case by following up with onboardUser","Back off on 429 and retry with a fresh token on 401"],"tags":["oauth","antigravity","google","upstream-api","token-expired"],"backgroundTag":"upstream-http-error","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}