From 3b80af299778270d9d8a8de49ab8185f722249bd Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Thu, 2 Apr 2026 18:49:33 -0400 Subject: [PATCH] log buffer contents on stream errors and timeouts Show chunks received, SSE lines parsed, and the contents of the line buffer (up to 500 bytes) on both stream errors and timeouts. This tells us whether we got partial data, a non-SSE response, or truly nothing from the server. Co-Authored-By: Proof of Concept --- src/agent/api/mod.rs | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/agent/api/mod.rs b/src/agent/api/mod.rs index 26bb293..fac187c 100644 --- a/src/agent/api/mod.rs +++ b/src/agent/api/mod.rs @@ -392,15 +392,37 @@ impl SseReader { } Ok(Ok(None)) => return Ok(None), Ok(Err(e)) => { - self.save_failed_request(&format!("stream error: {}", e)); + let buf_preview = if self.line_buf.is_empty() { + "(empty)".to_string() + } else { + let n = self.line_buf.len().min(500); + format!("{}B: {}", self.line_buf.len(), &self.line_buf[..n]) + }; + let msg = format!( + "stream error after {} chunks, {:.1}s, {} sse lines: {} | buf: {}", + self.chunks_received, + self.stream_start.elapsed().as_secs_f64(), + self.sse_lines_parsed, + e, buf_preview, + ); + let _ = self.ui_tx.send(UiMessage::Debug(msg.clone())); + self.save_failed_request(&msg); return Err(e.into()); } Err(_) => { + let buf_preview = if self.line_buf.is_empty() { + "(empty)".to_string() + } else { + let n = self.line_buf.len().min(500); + format!("{}B: {}", self.line_buf.len(), &self.line_buf[..n]) + }; let msg = format!( - "stream timeout: no data for {}s ({} chunks, {:.1}s elapsed)", + "stream timeout: {}s, {} chunks, {} sse lines, {:.1}s elapsed | buf: {}", self.chunk_timeout.as_secs(), self.chunks_received, - self.stream_start.elapsed().as_secs_f64() + self.sse_lines_parsed, + self.stream_start.elapsed().as_secs_f64(), + buf_preview, ); let _ = self.ui_tx.send(UiMessage::Debug(msg.clone())); self.save_failed_request(&msg);