Skip to content

Conversation

@sususu98
Copy link
Contributor

@sususu98 sususu98 commented Dec 8, 2025

Summary

  • Add fallback parsing for quota reset delay when RetryInfo is not present
  • Try ErrorInfo.metadata.quotaResetDelay (e.g., "373.801628ms")
  • Parse from error.message containing "Your quota will reset after Xs."

This ensures proper cooldown timing for rate-limited requests, as most Gemini CLI 429 responses only contain ErrorInfo without RetryInfo.

Test plan

  • Docker build successful
  • Verify cooldown uses API-provided retry delay instead of exponential backoff

🤖 Generated with Claude Code

Add fallback parsing for quota reset delay when RetryInfo is not present:
- Try ErrorInfo.metadata.quotaResetDelay (e.g., "373.801628ms")
- Parse from error.message "Your quota will reset after Xs."

This ensures proper cooldown timing for rate-limited requests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @sususu98, 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 significantly improves the Gemini CLI's ability to handle API rate limits by introducing multiple fallback strategies for determining the required retry delay. By parsing delay information from ErrorInfo.metadata and even the error message itself, the CLI can now more accurately adhere to server-specified cooldown periods, leading to more efficient and compliant retry behavior.

Highlights

  • Enhanced 429 Retry Delay Parsing: The Gemini CLI now includes more robust mechanisms for parsing retry delays from 429 (Too Many Requests) responses, ensuring proper cooldown timing for rate-limited requests.
  • Fallback for Missing RetryInfo: When RetryInfo is not present in the error details, the system will now attempt to parse the quotaResetDelay from ErrorInfo.metadata.
  • Error Message Parsing: A new fallback mechanism has been implemented to extract the retry delay directly from the error.message string, specifically looking for patterns like "Your quota will reset after Xs.".
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 enhances the parsing of 429 retry delays by adding fallback mechanisms. The changes correctly implement fallbacks to parse the delay from ErrorInfo.metadata.quotaResetDelay and from the error message text. My review includes suggestions to improve efficiency by combining loops and optimizing regular expression compilation. Overall, this is a good improvement for handling rate-limiting responses more robustly.

Comment on lines +771 to +800
if details.Exists() && details.IsArray() {
for _, detail := range details.Array() {
typeVal := detail.Get("@type").String()
if typeVal == "type.googleapis.com/google.rpc.RetryInfo" {
retryDelay := detail.Get("retryDelay").String()
if retryDelay != "" {
// Parse duration string like "0.847655010s"
duration, err := time.ParseDuration(retryDelay)
if err != nil {
return nil, fmt.Errorf("failed to parse duration")
}
return &duration, nil
}
}
}

// Fallback: try ErrorInfo.metadata.quotaResetDelay (e.g., "373.801628ms")
for _, detail := range details.Array() {
typeVal := detail.Get("@type").String()
if typeVal == "type.googleapis.com/google.rpc.ErrorInfo" {
quotaResetDelay := detail.Get("metadata.quotaResetDelay").String()
if quotaResetDelay != "" {
duration, err := time.ParseDuration(quotaResetDelay)
if err == nil {
return &duration, nil
}
}
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This implementation iterates over the details array twice: once for RetryInfo and a second time for ErrorInfo. This is inefficient. You can combine these into a single loop to improve performance and code clarity. By iterating once, you can check for RetryInfo and, if not found, use a fallback value from ErrorInfo that you've stored from the same loop.

    if details.Exists() && details.IsArray() {
        var errorInfoDelay string
        for _, detail := range details.Array() {
            typeVal := detail.Get("@type").String()
            if typeVal == "type.googleapis.com/google.rpc.RetryInfo" {
                if retryDelay := detail.Get("retryDelay").String(); retryDelay != "" {
                    duration, err := time.ParseDuration(retryDelay)
                    if err != nil {
                        return nil, fmt.Errorf("failed to parse duration")
                    }
                    return &duration, nil
                }
            }
            if typeVal == "type.googleapis.com/google.rpc.ErrorInfo" {
                if d := detail.Get("metadata.quotaResetDelay").String(); d != "" {
                    errorInfoDelay = d
                }
            }
        }

        if errorInfoDelay != "" {
            if duration, err := time.ParseDuration(errorInfoDelay); err == nil {
                return &duration, nil
            }
        }
    }

// Fallback: parse from error.message "Your quota will reset after Xs."
message := gjson.GetBytes(errorBody, "error.message").String()
if message != "" {
re := regexp.MustCompile(`after\s+(\d+)s\.?`)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Compiling a regular expression with regexp.MustCompile inside a function that can be called multiple times is inefficient. It's a Go best practice to compile regular expressions once at the package level and reuse the compiled object. This avoids the performance overhead of recompilation on every call to parseRetryDelay.

Consider defining it as a package-level variable:

var quotaResetMsgRegex = regexp.MustCompile(`after\s+(\d+)s\.?`)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant