decolua/9router · error · Error
Failed to fetch project ID: ${error}
Error message
Failed to fetch project ID: ${error} What it means
GeminiCLIService.fetchProjectId() (src/lib/oauth/services/gemini.js:85) calls Google's Cloud Code Assist endpoint (cloudcode-pa.googleapis.com/v1internal:loadCodeAssist) with the fresh access token to discover the user's cloudaicompanionProject. A non-2xx response is wrapped into 'Failed to fetch project ID: <body>' and thrown, mid-way through connect() after tokens were already obtained.
Source
Thrown at src/lib/oauth/services/gemini.js:85
{
method: "POST",
headers: {
"Authorization": `Bearer ${accessToken}`,
"Content-Type": "application/json",
"User-Agent": "google-api-nodejs-client/9.15.1",
"X-Goog-Api-Client": "google-cloud-sdk vscode_cloudshelleditor/0.1",
"Client-Metadata": JSON.stringify(getOAuthClientMetadata())
},
body: JSON.stringify({
metadata: getOAuthClientMetadata(),
mode: 1
})
}
);
if (!response.ok) {
const error = await response.text();
throw new Error(`Failed to fetch project ID: ${error}`);
}
const data = await response.json();
// Extract project ID
let projectId = "";
if (typeof data.cloudaicompanionProject === "string") {
projectId = data.cloudaicompanionProject.trim();
} else if (data.cloudaicompanionProject?.id) {
projectId = data.cloudaicompanionProject.id.trim();
}
if (!projectId) {
throw new Error("No project ID found in response");
}
return projectId;
}View on GitHub (pinned to 90b52e06ff)
Solutions
- Read the embedded body for the status code and Google error details (401/403 vs 429 vs 5xx).
- For 401/403: re-run connect(), approve ALL requested scopes on the consent screen, and verify the account has Gemini Code Assist available.
- For 429: wait and retry — the call is rate-limited per account.
- For 5xx: retry after a short backoff; if it persists, check whether Google changed the loadCodeAssist endpoint and update the URL/metadata in fetchProjectId.
- Confirm system clock correctness — a skewed clock invalidates bearer tokens right after exchange.
Example fix
// before
if (!response.ok) {
const error = await response.text();
throw new Error(`Failed to fetch project ID: ${error}`);
}
// after
if (!response.ok) {
const error = await response.text();
if (response.status >= 500 || response.status === 429) {
await new Promise((r) => setTimeout(r, 2000));
return this.fetchProjectId(accessToken); // transient — retry once
}
throw new Error(`Failed to fetch project ID (HTTP ${response.status}): ${error}`);
} Defensive patterns
Strategy: retry
Validate before calling
// pre-checks before the loadCodeAssist call
if (!accessToken) throw new Error("Access token required for loadCodeAssist");
// optionally verify token works first via getUserInfo(), which fails faster on 401 Type guard
function isTransientHttpError(status) {
return status === 429 || status >= 500;
} Try / catch
try {
const projectId = await geminiService.fetchProjectId(tokens.access_token);
} catch (err) {
const m = /Failed to fetch project ID: (.*)/s.exec(err.message);
if (m && /401|403/.test(m[1])) {
console.error("Account lacks Code Assist access or scopes were not granted — re-run connect() and approve all scopes.");
} else if (m && /429|5\d\d/.test(m[1])) {
console.error("Transient Google error — retry after backoff.");
} else throw err;
} Prevention
- Use a Google account with Gemini Code Assist enabled/onboarded.
- Approve all requested scopes on the consent screen; missing cloud-platform scope breaks this call.
- Keep the system clock accurate — skewed clocks invalidate fresh bearer tokens.
- Wrap project-ID fetch with bounded backoff retries for 429/5xx.
- Watch for Google changing the v1internal endpoint and pin a fallback.
When it happens
Trigger: Calling fetchProjectId(accessToken) when Google replies non-2xx — 401/403 when the token lacks the cloud-platform scope or the account has no Code Assist entitlement, 404 when the internal API shape/URL changed, 429 on quota, or 5xx from Google.
Common situations: The Google account is a Workspace account without Cloud Code Assist enabled; the user denied the requested scopes on the consent screen; Google changed the v1internal API contract (common for internal endpoints); transient Google-side outage right after login.
Related errors
- No project ID found in response
- Failed to get user info: ${error}
- Edge TTS voices fetch failed: ${res.status}
- Self-hosted TTS failed: ${res.status}
- loadCodeAssist failed: HTTP ${response.status} ${errorText.s
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/bdaf8aa9f8edfbc5.
Report an issue: GitHub.