Classify provider stream read failures

This commit is contained in:
Meta Vens 2026-08-24 23:36:53 +02:00
commit b2c0f8dd6b

View file

@ -500,7 +500,7 @@ fn parse_responses_sse(reader: impl Read) -> Result<ParsedProviderStream, &'stat
.by_ref()
.take((MAX_SSE_FRAME_BYTES + 1) as u64)
.read_until(b'\n', &mut line)
.map_err(|_| "provider SSE read failed")?;
.map_err(|error| provider_sse_read_error(error.kind()))?;
if read == 0 {
if !data.is_empty() {
state.accept_frame(&data)?;
@ -544,6 +544,18 @@ fn parse_responses_sse(reader: impl Read) -> Result<ParsedProviderStream, &'stat
})
}
fn provider_sse_read_error(kind: io::ErrorKind) -> &'static str {
match kind {
io::ErrorKind::TimedOut | io::ErrorKind::WouldBlock => "provider SSE read timed out",
io::ErrorKind::ConnectionReset
| io::ErrorKind::ConnectionAborted
| io::ErrorKind::BrokenPipe
| io::ErrorKind::NotConnected
| io::ErrorKind::UnexpectedEof => "provider SSE connection closed unexpectedly",
_ => "provider SSE read failed",
}
}
fn failed_result(
invocation: &CodexTransportInvocation,
failure_kind: &str,
@ -1037,6 +1049,14 @@ mod tests {
use std::net::TcpListener;
use std::thread;
struct FailingReader(io::ErrorKind);
impl Read for FailingReader {
fn read(&mut self, _buffer: &mut [u8]) -> io::Result<usize> {
Err(io::Error::from(self.0))
}
}
fn jwt(payload: Value) -> String {
let payload = URL_SAFE_NO_PAD.encode(serde_json::to_vec(&payload).unwrap());
format!("e30.{payload}.signature")
@ -1213,6 +1233,32 @@ mod tests {
);
}
#[test]
fn responses_stream_classifies_read_failures_without_exposing_io_details() {
for kind in [io::ErrorKind::TimedOut, io::ErrorKind::WouldBlock] {
assert_eq!(
parse_responses_sse(FailingReader(kind)).unwrap_err(),
"provider SSE read timed out"
);
}
for kind in [
io::ErrorKind::ConnectionReset,
io::ErrorKind::ConnectionAborted,
io::ErrorKind::BrokenPipe,
io::ErrorKind::NotConnected,
io::ErrorKind::UnexpectedEof,
] {
assert_eq!(
parse_responses_sse(FailingReader(kind)).unwrap_err(),
"provider SSE connection closed unexpectedly"
);
}
assert_eq!(
parse_responses_sse(FailingReader(io::ErrorKind::Other)).unwrap_err(),
"provider SSE read failed"
);
}
#[test]
fn provider_http_transmits_exact_body_and_required_identity_headers() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap();