fix(gemini): session expired#363
Conversation
|
@codex review |
There was a problem hiding this comment.
Pull request overview
Fixes recurring Gemini “session expired” failures by improving how the plugin discovers the Gemini CLI OAuth client credentials (oauth2.js) across common global install/version-manager layouts, enabling token refresh to succeed more reliably.
Changes:
- Replace the static
oauth2.jspath list with dynamic candidate path generation (static roots + nested layouts + NVM/FNM scanning + Volta paths). - Improve logging to include the failing
oauth2.jspath when a read/parse attempt errors, and warn when no credentials can be found. - Add test coverage for NVM version scanning discovery, nested dependency layouts, and the “no oauth2.js found” warning behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| plugins/gemini/plugin.js | Dynamically builds candidate oauth2.js paths (including version-manager scanning) and improves warning logs when credentials cannot be read/found. |
| plugins/gemini/plugin.test.js | Adds tests validating the new discovery strategies and warning behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| function loadOauthClientCreds(ctx) { | ||
| for (let i = 0; i < OAUTH2_JS_PATHS.length; i += 1) { | ||
| const path = OAUTH2_JS_PATHS[i] | ||
| const candidates = buildOauthCandidatePaths(ctx) | ||
| for (let i = 0; i < candidates.length; i += 1) { | ||
| const path = candidates[i] | ||
| if (!ctx.host.fs.exists(path)) continue | ||
| try { | ||
| const parsed = parseOauthClientCreds(ctx.host.fs.readText(path)) | ||
| if (parsed) return parsed | ||
| } catch (e) { | ||
| ctx.host.log.warn("failed reading oauth2.js: " + String(e)) | ||
| ctx.host.log.warn("failed reading oauth2.js at " + path + ": " + String(e)) | ||
| } | ||
| } | ||
| ctx.host.log.warn("Gemini OAuth client credentials not found in any known install path") | ||
| return null |
There was a problem hiding this comment.
loadOauthClientCreds logs a warning every time no oauth2.js match is found. Since refreshToken() can be invoked multiple times in a single probe() (initial refresh + retryOnceOnAuth for loadCodeAssist + quota), this can emit the same warning multiple times per probe and spam logs. Consider memoizing the “not found” result (e.g., module-scoped warnedMissingOauth2 flag) and/or caching the resolved client creds so the warning is emitted at most once per process/session.
| function buildOauthCandidatePaths(ctx) { | ||
| var paths = [] | ||
|
|
||
| for (var i = 0; i < STATIC_MODULE_ROOTS.length; i += 1) { | ||
| paths.push(STATIC_MODULE_ROOTS[i] + OAUTH2_SUFFIX_FLAT) | ||
| paths.push(STATIC_MODULE_ROOTS[i] + OAUTH2_SUFFIX_NESTED) | ||
| } | ||
|
|
||
| for (var i = 0; i < STATIC_NESTED_ONLY.length; i += 1) { | ||
| paths.push(STATIC_NESTED_ONLY[i] + OAUTH2_SUFFIX_NESTED) | ||
| } | ||
|
|
||
| for (var i = 0; i < VERSION_MANAGER_ROOTS.length; i += 1) { | ||
| var root = VERSION_MANAGER_ROOTS[i] | ||
| var versions = listDirSafe(ctx, root) | ||
| for (var j = 0; j < versions.length; j += 1) { | ||
| var base = root + "/" + versions[j] + "/lib/node_modules" | ||
| paths.push(base + OAUTH2_SUFFIX_FLAT) | ||
| paths.push(base + OAUTH2_SUFFIX_NESTED) | ||
| } | ||
| } | ||
|
|
||
| // volta stores packages differently | ||
| paths.push("~/.volta/tools/image/packages/@google/gemini-cli/lib/node_modules" + OAUTH2_SUFFIX_NESTED) | ||
| paths.push("~/.volta/tools/image/packages/@google/gemini-cli/lib/node_modules" + OAUTH2_SUFFIX_FLAT) | ||
|
|
||
| return paths |
There was a problem hiding this comment.
buildOauthCandidatePaths() does directory listings and builds a potentially large candidate list on every call to loadOauthClientCreds(). Because refresh may be attempted multiple times per probe() (and probes may run frequently), this can lead to repeated filesystem work. Consider caching the computed candidate paths and/or caching the parsed OAuth client credentials after the first successful read to avoid rescanning on subsequent refresh attempts.
|
Codex Review: Didn't find any major issues. Bravo. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@yhunko please resolve the conversations and we can continue after that. thanks! |
Description
Fixes Gemini session expired issue
Related Issue
Fixes #357
Type of Change
Testing
bun run buildand it succeededbun run testand all tests passbun tauri devChecklist
mainbranchSummary by cubic
Fixes Gemini “session expired” by reliably finding OAuth client credentials and refreshing tokens across common install paths. Adds clear warnings when none are found; fixes #357.
@google/gemini-cli-core/@google/gemini-clioauth2.js in flat and nested layouts (NVM, FNM with corrected~/Library/Application Support/fnm/.../installationpath, Volta, npm/pnpm globals, Homebrew,/usr/local).~/.gemini/oauth_creds.json.Written for commit 7735d12. Summary will update on new commits.