Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ oci.tar
.claude
.DS_Store
secret
repro_*.sh
22 changes: 18 additions & 4 deletions crates/services/src/completions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ where
last_usage_stats: Option<inference_providers::TokenUsage>,
/// Last chat ID from streaming chunks (for attestation and inference_id)
last_chat_id: Option<String>,
/// Flag indicating the stream completed normally (received None from inner stream)
/// If false when Drop is called, the client disconnected mid-stream
/// Flag indicating the stream completed normally (received None from inner stream).
/// If false when Drop is called, the stream was interrupted — either the client
/// disconnected mid-stream or the provider returned an error (check `last_error`).
stream_completed: bool,
/// Response ID when called from Responses API (for usage tracking FK)
response_id: Option<ResponseId>,
Expand Down Expand Up @@ -171,11 +172,24 @@ where
chat_id.clone(),
),
(None, None) => {
tracing::error!(%organization_id, %model_id, "Stream ended but no usage stats and no chat_id available");
// Distinguish client disconnect / provider error from truly unexpected cases.
// Client disconnects and provider errors are expected — usage is only sent
// in the final chunk, so an interrupted stream will never have it.
if !self.stream_completed {
tracing::warn!(%organization_id, %model_id, stream_error = self.last_error.is_some(),
"Stream interrupted before usage stats or chat_id received (client disconnect or provider error)");
} else {
tracing::error!(%organization_id, %model_id, "Stream completed but no usage stats and no chat_id available");
}
return;
}
(None, Some(chat_id)) => {
tracing::error!(%chat_id, %organization_id, %model_id, "Stream ended but no usage stats available");
if !self.stream_completed {
tracing::warn!(%chat_id, %organization_id, %model_id, stream_error = self.last_error.is_some(),
"Stream interrupted before usage stats received (client disconnect or provider error)");
} else {
tracing::error!(%chat_id, %organization_id, %model_id, "Stream completed but no usage stats available");
}
return;
}
(Some(usage), None) => {
Expand Down
Loading