msgraph-sdk-python icon indicating copy to clipboard operation
msgraph-sdk-python copied to clipboard

ValueError When Handling Retry-After Headers After 429 Too Many Requests Error

Open gilron07 opened this issue 8 months ago • 4 comments

Describe the bug

The issue arises after encountering a 429 Too Many Requests error, which likely returns an incorrect Retry-After header value like 30,120 (representing two retry times or a malformed retry interval). When the retry handler attempts to process this value, it throws an error because it cannot properly parse the value into an integer due to the comma.

<kiota_http.middleware.retry_handler.RetryHandler object at 0x1104f2780>
retry_after = '30,120'

    def _parse_retry_after(self, retry_after):
        """
        Helper to parse Retry-After and get value in seconds.
        """
        try:
>           delay = int(retry_after)
E           ValueError: invalid literal for int() with base 10: '30,120'

Expected behavior

  • Server returns proper Retry After value
  • Client is able to properly parse value & retry request or if still gets 429, throw an appropriate HTTP exception.

How to reproduce

Steps to Reproduce:

  • Trigger a 429 Too Many Requests error by sending multiple simultaneous requests to sites graph endpoint: client.sites.get(request_configuration=request)

  • Observe that the Retry-After header contains the value "30,120".

  • The retry handler fails with the error ValueError: invalid literal for int() with base 10: '30,120'.

SDK Version

1.26.0

Latest version known to work for scenario above?

No response

Known Workarounds

No response

Debug output

Click to expand log ``` self = retry_after = '30,120'
def _parse_retry_after(self, retry_after):
    """
    Helper to parse Retry-After and get value in seconds.
    """
    try:
      delay = int(retry_after)

E ValueError: invalid literal for int() with base 10: '30,120'

../.venv/lib/python3.xx/site-packages/kiota_http/middleware/retry_handler.py:205: ValueError

</details>


### Configuration

_No response_

### Other information

_No response_

gilron07 avatar Mar 25 '25 18:03 gilron07

Experiencing the exact same problem!

MarcoP9 avatar Mar 27 '25 16:03 MarcoP9

Hello! Is there any update on this? What could be a possible workaround?

MarcoP9 avatar Apr 10 '25 09:04 MarcoP9

same here

metealp avatar Apr 14 '25 11:04 metealp

@gilron07 good catch. This seems to be a casting issue in the http retry middleware. https://github.com/microsoft/kiota-python/blob/cc340dcc928bbee96a7abb7c18752b892684fc83/packages/http/httpx/kiota_http/middleware/retry_handler.py#L200-L210

Updating this to cater for the returned comma-separated ints and pick the correct one should do the trick. Are you interested in picking this up?

musale avatar Apr 15 '25 13:04 musale

Hi @musale thank you for your answer, would something like the following work?

def _parse_retry_after(self, retry_after):
        """
        Helper to parse Retry-After and get value in seconds.
        """
        try:
            retry_after= retry_after.split(",")[0] if "," in retry_after else retry_after
            delay = int(retry_after)
        except ValueError:
            # Not an integer? Try HTTP date
            retry_date = parsedate_to_datetime(retry_after)
            delay = (retry_date - datetime.datetime.now(retry_date.tzinfo)).total_seconds()
        return max(0, delay)

You mention to:

Updating this to cater for the returned comma-separated ints and pick the correct one should do the trick. Are you interested in picking this up?

But which is the correct value? 30 or 120? Why is the server answering with "30,120"?

Thank you!

MarcoP9 avatar Jun 18 '25 10:06 MarcoP9

I got a same error, right now.

s-nakagaki avatar Jun 23 '25 10:06 s-nakagaki