{"record":{"id":"57fa71a1dcc804b1","repo":"can1357/oh-my-pi","slug":"google-cloud-credentials-missing-projectid","errorCode":null,"errorMessage":"Google Cloud credentials missing projectId","messagePattern":"Google Cloud credentials missing projectId","errorType":"exception","errorClass":"AIError.ConfigurationError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/registry/google-gemini-cli.ts","lineNumber":15,"sourceCode":"import * as AIError from \"../error\";\nimport type { OAuthCredentials, OAuthLoginCallbacks } from \"./oauth/types\";\nimport type { ProviderDefinition } from \"./types\";\n\nexport const googleGeminiCliProvider = {\n\tid: \"google-gemini-cli\",\n\tname: \"Google Cloud Code Assist (Gemini CLI)\",\n\tlogin: async (cb: OAuthLoginCallbacks) => {\n\t\t// Lazy import: keep heavy OAuth flow modules out of the eager registry graph.\n\t\tconst { loginGeminiCli } = await import(\"./oauth/google-gemini-cli\");\n\t\treturn loginGeminiCli(cb);\n\t},\n\trefreshToken: async (credentials: OAuthCredentials) => {\n\t\tif (!credentials.projectId) {\n\t\t\tthrow new AIError.ConfigurationError(\"Google Cloud credentials missing projectId\");\n\t\t}\n\t\tconst { refreshGoogleCloudToken } = await import(\"./oauth/google-gemini-cli\");\n\t\treturn refreshGoogleCloudToken(credentials.refresh, credentials.projectId);\n\t},\n\tcallbackPort: 8085,\n\tpasteCodeFlow: true,\n} as const satisfies ProviderDefinition;\n","sourceCodeStart":1,"sourceCodeEnd":23,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/registry/google-gemini-cli.ts#L1-L23","documentation":"Google Cloud (Gemini CLI) OAuth credentials must include a projectId because token refresh calls refreshGoogleCloudToken(refresh, projectId) — Google's token exchange requires the cloud project context. When stored credentials lack projectId, the registry's refreshToken hook throws this ConfigurationError before making any network call. Login normally populates it, so this indicates incomplete or legacy credentials.","triggerScenarios":"Calling the registry's refreshToken (or any automatic refresh path) with OAuthCredentials whose projectId is null/undefined — e.g. credentials from an older login flow, hand-edited auth state, or programmatically built credential objects.","commonSituations":"Stale credentials predating the projectId requirement; copying an auth file between machines with partial contents; a Gemini CLI OAuth flow that was interrupted before project selection; scripted credential provisioning omitting the field.","solutions":["Re-run /login (loginGeminiCli) to regenerate credentials including projectId.","Set the projectId explicitly in the stored credentials if known (the Google Cloud project used at login).","Inspect the stored credential file for a missing/null projectId and restore it.","Ensure the library version that wrote the credentials matches the version reading them (schema drift)."],"exampleFix":"// before\nawait registry.refreshToken({ refresh: \"1//abc\", projectId: undefined });\n// throws ConfigurationError\n// after\nconst creds = await registry.login(callbacks); // captures projectId\nawait registry.refreshToken(creds);","handlingStrategy":"try-catch","validationCode":"// before triggering a refresh\nif (!credentials.projectId) {\n  await reloginGeminiCli(); // recapture credentials including projectId\n}","typeGuard":"function hasProjectId(c: OAuthCredentials): c is OAuthCredentials & { projectId: string } {\n  return typeof c.projectId === \"string\" && c.projectId.length > 0;\n}","tryCatchPattern":"try {\n  await registry.refreshToken(credentials);\n} catch (err) {\n  if (err instanceof AIError.ConfigurationError && /missing projectId/.test(err.message)) {\n    credentials = await registry.login(callbacks);\n    await registry.refreshToken(credentials);\n  } else throw err;\n}","preventionTips":["Complete the full Gemini CLI OAuth flow (project selection) instead of aborting midway.","Regenerate credentials after version upgrades that alter the auth schema.","Validate projectId presence when loading persisted auth state.","Don't sync partial credential files between machines."],"tags":["oauth","google-cloud","configuration","credentials","token-refresh"],"backgroundTag":"missing-credential-field","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}