Skip to content

fix: preserve caller-supplied timeout across all retry attempts in request_with_retry#11386

Open
devteamaegis wants to merge 1 commit into
deepset-ai:mainfrom
devteamaegis:fix/request-with-retry-timeout-pop
Open

fix: preserve caller-supplied timeout across all retry attempts in request_with_retry#11386
devteamaegis wants to merge 1 commit into
deepset-ai:mainfrom
devteamaegis:fix/request-with-retry-timeout-pop

Conversation

@devteamaegis
Copy link
Copy Markdown
Contributor

What

request_with_retry and async_request_with_retry accept a timeout kwarg, but that timeout was silently ignored on every retry after the first.

Root cause

timeout was popped from kwargs inside the @retry-decorated run() closure:

# Before (inside run())
def run() -> httpx.Response:
    timeout = kwargs.pop("timeout", 10)   # <-- pops on attempt 1…
    with httpx.Client() as client:
        res = client.request(**kwargs, timeout=timeout)

kwargs.pop mutates the dict in-place. On the first attempt the caller's value is consumed. On every subsequent retry the key is gone, so kwargs.pop("timeout", 10) returns the hardcoded default (10) regardless of what the caller passed.

Fix

Move the pop to before the @retry decoration — once, not once-per-attempt — so the closed-over timeout variable holds the right value for every attempt:

# After (outside run(), before @retry)
timeout = kwargs.pop("timeout", 10)

@retry(...)
def run() -> httpx.Response:
    with httpx.Client() as client:
        res = client.request(**kwargs, timeout=timeout)

The same fix is applied to async_request_with_retry.

Tests

Added test_request_with_retry_preserves_timeout_on_retry and test_async_request_with_retry_preserves_timeout_on_retry. Each test makes the first attempt fail with a RequestError so a retry is triggered, then asserts that both calls to httpx.Client.request / httpx.AsyncClient.request received the caller-supplied timeout=42, not the default 10.

…quest_with_retry

`timeout` was popped from `kwargs` *inside* the `@retry`-decorated `run()`
closure.  On the first attempt `kwargs.pop("timeout", 10)` consumed the key
and used the caller's value; on all subsequent retries the key was gone, so
the pop silently fell back to the hardcoded 10-second default — completely
ignoring whatever the caller had passed.

The fix moves both `kwargs.pop("timeout", 10)` calls (sync and async
variants) to just before the `@retry` decoration so they execute once and
the closed-over `timeout` variable is reused on every attempt.

Adds two regression tests that verify the custom timeout is forwarded on
every attempt, including retries triggered by a transient `RequestError`.
@devteamaegis devteamaegis requested a review from a team as a code owner May 24, 2026 01:47
@devteamaegis devteamaegis requested review from julian-risch and removed request for a team May 24, 2026 01:47
@vercel
Copy link
Copy Markdown

vercel Bot commented May 24, 2026

Someone is attempting to deploy a commit to the deepset Team on Vercel.

A member of the Team first needs to authorize it.

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


devteamaegis seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@julian-risch
Copy link
Copy Markdown
Member

@devteamaegis Thank you for opening this PR. Could you please agree to our CLA? #11386 (comment)

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants