Skip to content

Conversation

@kevin-ramdass
Copy link
Contributor

Summary

Implemented an explicit 60-second client-side timeout for API calls to prevent the default 5-minute hang when the backend/proxy is unresponsive.

Details

  • Added TIMEOUT_MS (60s) constant to packages/core/src/core/geminiChat.ts.
  • Wrapped generateContentStream with AbortSignal.timeout merged with the user's abort signal.
  • Mapped timeout errors to ETIMEDOUT code to ensure they are caught by retryWithBackoff and automatically retried.
  • Added unit test should throw ETIMEDOUT when request times out in geminiChat.test.ts.

Related Issues

Fixes #18030

How to Validate

Run the specific unit test for this feature:

npm test -w @google/gemini-cli-core -- src/core/geminiChat.test.ts

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @kevin-ramdass, 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 introduces a crucial reliability enhancement by implementing an explicit client-side timeout for API calls within the core geminiChat module. This change prevents the application from hanging indefinitely when facing unresponsive backend services or network issues, ensuring a more robust and predictable user experience. By standardizing timeout errors, it also facilitates proper error handling and retry logic.

Highlights

  • Explicit API Timeout: Implemented a 60-second client-side timeout for API calls to prevent indefinite hangs when the backend or proxy is unresponsive.
  • Combined Abort Signals: The generateContentStream function now uses a combined AbortSignal that merges the user's provided signal with a new AbortSignal.timeout.
  • Standardized Timeout Error: Timeout errors are caught and re-thrown with an ETIMEDOUT code, ensuring compatibility with existing retry mechanisms like retryWithBackoff.
  • New Unit Test: A dedicated unit test has been added to geminiChat.test.ts to verify the correct behavior of the timeout mechanism and ETIMEDOUT error propagation.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize 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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. 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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an explicit client-side timeout for API calls, which is a great improvement to prevent the application from hanging. The implementation correctly uses AbortSignal.timeout and AbortSignal.any to combine signals. However, there is a critical flaw in where the timeout error is handled, which will prevent it from working as intended in the real application. I've left a detailed comment on the specific block of code, emphasizing the correct use of AbortSignal for cancellation and timeout handling.

Comment on lines 594 to 612
try {
return await this.config.getContentGenerator().generateContentStream(
{
model: modelToUse,
contents: contentsToUse,
config,
},
prompt_id,
);
} catch (error) {
if (timeoutSignal.aborted) {
const timeoutError = new Error(
`Request timed out after ${TIMEOUT_MS}ms`,
);
(timeoutError as unknown as { code: string }).code = 'ETIMEDOUT';
throw timeoutError;
}
throw error;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This try...catch block incorrectly assumes the timeout error will be thrown during the creation of the async generator. However, generateContentStream returns a generator, and the underlying network request that can time out only happens when this generator is consumed.

The consumption happens later in processStreamResponse, so the timeout error will be thrown there and propagate to a catch block that doesn't have access to timeoutSignal. This means the timeout won't be correctly identified and retried.

The fix involves moving this try...catch logic to where the stream is consumed inside processStreamResponse. You'll need to pass timeoutSignal down to processStreamResponse to check timeoutSignal.aborted in the new catch block.

      return await this.config.getContentGenerator().generateContentStream(
        {
          model: modelToUse,
          contents: contentsToUse,
          config,
        },
        prompt_id,
      );
References
  1. The comment highlights an issue where the AbortSignal (referred to as timeoutSignal) is not being correctly leveraged for identifying and retrying timeout errors due to incorrect try...catch placement. This aligns with the principle of relying on AbortSignal for cancellation and consistent timeout handling in asynchronous operations, rather than implementing separate or incorrectly placed timeout mechanisms.
@github-actions
Copy link

github-actions bot commented Jan 31, 2026

Size Change: +1.23 kB (+0.01%)

Total Size: 23.6 MB

Filename Size Change
./bundle/gemini.js 23.6 MB +1.23 kB (+0.01%)
ℹ️ View Unchanged
Filename Size
./bundle/sandbox-macos-permissive-closed.sb 1.03 kB
./bundle/sandbox-macos-permissive-open.sb 890 B
./bundle/sandbox-macos-permissive-proxied.sb 1.31 kB
./bundle/sandbox-macos-restrictive-closed.sb 3.29 kB
./bundle/sandbox-macos-restrictive-open.sb 3.36 kB
./bundle/sandbox-macos-restrictive-proxied.sb 3.56 kB

compressed-size-action

@gemini-cli gemini-cli bot added area/core Issues related to User Interface, OS Support, Core Functionality priority/p1 Important and should be addressed in the near term. 🔒 maintainer only ⛔ Do not contribute. Internal roadmap item. labels Jan 31, 2026
…ntent generation and update mock to return an AsyncGenerator.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core Issues related to User Interface, OS Support, Core Functionality 🔒 maintainer only ⛔ Do not contribute. Internal roadmap item. priority/p1 Important and should be addressed in the near term.

1 participant