Files
hermes-agent/tests
Justas Cesnauskas b1aa0a9be0 fix(auxiliary): the watchdog Timer shuts the attempt stream's socket down instead of closing the stream
_CodexStreamGuard._close_client_on_timeout keeps the FD-ownership contract for the client's pool sockets
(shutdown() from the Timer, close() only on the owning thread), but then called close_attempt_stream(),
and an SDK Stream.close() on an unfinished response ends in sock.close() (httpx Response.close ->
httpcore HTTP11Connection.close -> SyncStream.close). That releases the descriptor while the owner is
still inside SSL_read: the kernel hands the number to the next open() and OpenSSL writes a TLS alert
record into that file. Two SQLite files in a gateway process lost bytes 5..28 of their header this way
(b"SQLit" + 17 03 03 00 13 ...), 15 ms after "Codex auxiliary client aborted (timeout,
tcp_force_closed=1, deferred_close=stranger_thread)".

close_attempt_stream() now does a real close() only on the owning thread. From any other thread it
shuts down the socket under the stream (stream.response.extensions["network_stream"]), which wakes the
reader and keeps the FD; the owner closes the stream in its finally (release_stream). A stream with no
reachable socket (a test double, a non-httpx transport) is closed as before.

Fixes #130115. Follow-up to #70773.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 33cfb5ea6550f4a56ea0faa072ddf7f91412af49)
2026-10-03 16:35:32 +05:30
..