fix(cli): handle refreshAuth rejection in non-interactive prompt path#26932
fix(cli): handle refreshAuth rejection in non-interactive prompt path#26932Eswar809 wants to merge 1 commit into
Conversation
The second refreshAuth call inside main()'s non-interactive prompt flow ran unguarded, so a transient network error during OAuth token refresh or the experiments fetch (e.g. ECONNRESET against cloudcode-pa.googleapis.com) surfaced as an unhandled promise rejection and crashed the CLI before any user-facing message could be printed. Wrap the call in a try/catch that reports the error to stderr, logs the full detail via debugLogger, and exits with FATAL_AUTHENTICATION_ERROR after running the registered cleanup hooks, matching the existing pattern used by the earlier pre-sandbox refreshAuth attempt. Fixes google-gemini#25739
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses a stability issue in the CLI where transient network errors during the non-interactive authentication flow caused the process to crash ungracefully. By introducing robust error handling, the CLI now catches these failures, logs them appropriately, and performs necessary cleanup before exiting, improving the overall user experience and debuggability. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces error handling for authentication refreshes in non-interactive mode within the Gemini CLI. Specifically, it wraps the refreshAuth call in a try-catch block to surface network or authentication errors (like ECONNRESET) as fatal errors instead of allowing them to cause unhandled crashes. A corresponding test case was added to verify this behavior. Feedback was provided regarding the test implementation, recommending the use of vi.stubEnv() for environment variable manipulation to align with the project's style guide and improve test reliability.
| process.env['GEMINI_API_KEY'] = 'test-key'; | ||
| try { | ||
| await main(); | ||
| expect.fail('Should have thrown MockProcessExitError'); | ||
| } catch (e) { | ||
| expect(e).toBeInstanceOf(MockProcessExitError); | ||
| expect((e as MockProcessExitError).code).toBe( | ||
| ExitCodes.FATAL_AUTHENTICATION_ERROR, | ||
| ); | ||
| } finally { | ||
| delete process.env['GEMINI_API_KEY']; | ||
| } |
There was a problem hiding this comment.
The repository style guide recommends using vi.stubEnv() instead of modifying process.env directly in tests to prevent test leakage and improve reliability. Since afterEach in this file already calls vi.unstubAllEnvs(), you can also remove the manual cleanup in the finally block.
vi.stubEnv('GEMINI_API_KEY', 'test-key');
try {
await main();
expect.fail('Should have thrown MockProcessExitError');
} catch (e) {
expect(e).toBeInstanceOf(MockProcessExitError);
expect((e as MockProcessExitError).code).toBe(
ExitCodes.FATAL_AUTHENTICATION_ERROR,
);
}
References
- Avoid modifying process.env directly; use vi.stubEnv instead. (link)
Summary
The second
refreshAuthcall insidemain()'s non-interactive prompt flow ran unguarded, so a transient network error during OAuth token refresh or theexperiments fetch (e.g.
ECONNRESETagainstcloudcode-pa.googleapis.com) surfaced as an unhandled promise rejection and crashed the CLI before anyuser-facing message could be printed.
Wrap the call in a try/catch that reports the error to stderr, logs the full detail via
debugLogger, and exits withFATAL_AUTHENTICATION_ERRORafterrunning the registered cleanup hooks — matching the existing pattern used by the earlier pre-sandbox
refreshAuthattempt.Fixes #25739
Test plan
"should exit with FATAL_AUTHENTICATION_ERROR when refreshAuth rejects in non-interactive mode"passes — asserts exit code, thatrunNonInteractiveis not reached, and that refreshAuth was called with the resolved auth typemainwithout the fix)npm run preflightexit 0