Skip to content

Interactions API does not retry connection errors despite HttpRetryOptions #3204

Open

Description

@fcakyon

Environment

  • google-genai 2.32.0, and current main (92f72b3, released as 2.33.0)
  • httpx 0.28.1 and httpx2 2.7.0, Python 3.10 and 3.12

Description

client.interactions never retries transport failures such as httpx.ConnectError. Retryable status codes are retried as configured, and _translate_retry_config always sets retry_connection_errors=True, but a connection error surfaces on the first attempt. In production this showed up as APIConnectionError: [Errno 9] Bad file descriptor from client.interactions.create, with no retry.

Reproduction

No network or real API key needed:

import asyncio

import httpx
from google import genai
from google.genai import types


def count_attempts(failure, use_async):
    requests = []

    def handler(request):
        requests.append(request)
        if failure == "ConnectError":
            raise httpx.ConnectError("[Errno 9] Bad file descriptor", request=request)
        return httpx.Response(503, json={"error": {"code": 503, "message": "unavailable"}})

    client = genai.Client(
        api_key="fake-key",
        http_options=types.HttpOptions(
            retry_options=types.HttpRetryOptions(attempts=3, initial_delay=0.01, max_delay=0.01),
            **{"async_client_args" if use_async else "client_args": {"transport": httpx.MockTransport(handler)}},
        ),
    )
    try:
        if use_async:
            asyncio.run(client.aio.interactions.create(model="gemini-3.5-flash", input="hi"))
        else:
            client.interactions.create(model="gemini-3.5-flash", input="hi")
    except Exception as e:
        return f"{len(requests)} attempt(s), raised {type(e).__name__}"


print(f"google-genai {genai.__version__}, httpx {httpx.__version__}")
for failure in ("503", "ConnectError"):
    for use_async in (False, True):
        print(f"{failure:>12} {'async' if use_async else 'sync':5}: {count_attempts(failure, use_async)}")

Output on main (2.32.0 prints the same counts):

google-genai 2.33.0, httpx 0.28.1
         503 sync : 4 attempt(s), raised InternalServerError
         503 async: 4 attempt(s), raised InternalServerError
ConnectError sync : 1 attempt(s), raised APIConnectionError
ConnectError async: 1 attempt(s), raised APIConnectionError

The httpx2 client (GOOGLE_GENAI_HTTP_CLIENT=httpx2 with httpx2.ConnectError) also makes 1 attempt.

Expected: the ConnectError case retries like the 503 case (4 attempts), then raises APIConnectionError.

Root cause

  1. BaseSDK.do_request runs the after_error hooks inside the per-attempt do() function (_gaos/basesdk.py).
  2. CompatErrorHook.after_error (_gaos/lib/compat_errors.py) calls wrap_sdk_error, which turns the httpx.ConnectError into APIConnectionError.
  3. retry() in _gaos/utils/retries.py then calls _is_transport_error, which only matches httpx NetworkError / TimeoutException by type or MRO name. APIConnectionError matches neither, so the error becomes a PermanentError and is raised without a retry.

test_httpx2_retries passes a raw httpx2.NetworkError to retries.retry directly, so it skips the hook and cannot catch this.

Public methods in _gaos/google_genai.py already wrap their calls in wrap_sdk_call, which applies the same translation after the retry loop, so the hook can leave errors raw. The one exception is environments.files.upload, which calls self._internal.start_upload directly, so the PR wraps that call too.

The models path had the same class of bug, fixed in #2345 (httpx) and #3186 (aiohttp).

Separately, _translate_retry_config passes HttpRetryOptions.attempts through as max_retries, so attempts=3 sends 4 requests, while the field is documented as "Maximum number of attempts, including the original request".

Activity

  1. added
    priority: p2Moderately-important priority. Fix may not be included in next release.
    type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.
    on Oct 23, 2026
  2. Venkaiahbabuneelam commented on Oct 23, 2026

    @Venkaiahbabuneelam

    Hi @fcakyon, Thank you for bringing this to our attention. We truly appreciate you flagging this issue, we will file a bug internally.
    Thanks

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

Metadata

Metadata

Labels

priority: p2Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions