Skip to content

HttpProxySink timeout failures can skip the configured spool fallback #3641

Description

@luochen211

Please read this first

  • I have read the Agents SDK docs.
  • I searched for related issues and did not find one for HttpProxySink TimeoutError spool.

Describe the bug

HttpProxySink has a spool fallback for failed HTTP delivery, but it only catches HTTPError and URLError:

try:
    with urlopen(req, timeout=self.timeout_s) as resp:
        _ = resp.read(1)
except (HTTPError, URLError) as e:
    if spool_line is not None and self.spool_path is not None:
        ... write spool_line ...
    raise RuntimeError(...)

Timeouts raised directly as TimeoutError / socket timeout during connect or read are not caught by this block. In that case, the configured spool_path fallback can be skipped and the caller sees a raw timeout exception instead of the sink's RuntimeError wrapper.

Debug information

  • Agents SDK version: main branch
  • Python version: N/A, code inspection

Repro steps

A small monkeypatch demonstrates the missed fallback path:

from pathlib import Path
from unittest.mock import patch

from agents.sandbox.session.sinks import HttpProxySink

sink = HttpProxySink(
    "http://127.0.0.1:9/events",
    timeout_s=0.001,
    spool_path=Path("/tmp/agents-events.jsonl"),
)

# If urlopen raises TimeoutError directly, HttpProxySink._post does not catch it,
# so the spool write branch is skipped.
with patch("agents.sandbox.session.sinks.urlopen", side_effect=TimeoutError("timed out")):
    sink._post(b"{}", '{"event":"example"}\n')

Code path:

  1. Open src/agents/sandbox/session/sinks.py.
  2. Inspect HttpProxySink._post().
  3. Observe that the failure/spool branch catches (HTTPError, URLError) only.
  4. Direct TimeoutError exceptions bypass the spool branch.

Expected behavior

HttpProxySink should treat timeout exceptions like other delivery failures: write the spool line when configured, then raise the sink's RuntimeError wrapper. Catching TimeoutError (and possibly OSError) alongside HTTPError/URLError would make the fallback behavior consistent.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions