From 811885274bf2a7a6a337711a187e74b3477e899a Mon Sep 17 00:00:00 2001 From: hobokenchicken Date: Thu, 5 Mar 2026 17:34:40 +0000 Subject: [PATCH] fix(gemini): handle 'Stream ended' gracefully and improve debug logging --- src/providers/gemini.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/providers/gemini.rs b/src/providers/gemini.rs index d16011c9..c03bf28f 100644 --- a/src/providers/gemini.rs +++ b/src/providers/gemini.rs @@ -848,11 +848,12 @@ impl super::Provider for GeminiProvider { let gemini_response: GeminiStreamResponse = serde_json::from_str(&msg.data) .map_err(|e| AppError::ProviderError(format!("Failed to parse stream chunk: {}", e)))?; - tracing::info!("Received Gemini stream chunk (candidates: {}, has_usage: {})", + tracing::info!("Received Gemini stream chunk (candidates: {}, has_usage: {}, finish_reason: {:?})", gemini_response.candidates.len(), - gemini_response.usage_metadata.is_some() + gemini_response.usage_metadata.is_some(), + gemini_response.candidates.first().and_then(|c| c.finish_reason.as_deref()) ); - + // Extract usage from usageMetadata if present (reported on every/last chunk) let stream_usage = gemini_response.usage_metadata.as_ref().map(|u| { super::StreamUsage { @@ -967,6 +968,12 @@ impl super::Provider for GeminiProvider { } Ok(_) => continue, Err(e) => { + // "Stream ended" is usually a normal EOF signal in reqwest-eventsource. + // We check the string representation to avoid returning it as an error. + if e.to_string().contains("Stream ended") { + break; + } + // On stream error, attempt to probe for the actual error body from the provider let probe_resp = probe_client .post(&probe_url)