mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
fix(logging): restore consumer context only after stream-failure exception mapping
_map_anthropic_exception/_map_aleph_alpha_exception synchronously log a debug diagnostic (the raw status code) as part of exception_type()'s mapping. _handle_stream_fallback_error restored the consumer's outer correlation context before calling exception_type(), so that diagnostic log line carried the outer (or empty) trace_id/session_id instead of the failing stream's own - flagged by Greptile. Moved the restore to run after mapping completes, matching the same restore-after-not-before pattern already applied elsewhere in this file for success/finish_reason handling. Added a regression test that captures the correlation context live during a mocked exception_type() call; fails against the prior commit, passes now.
This commit is contained in:
parent
54a3d8c969
commit
f1cf9589d6
2 changed files with 56 additions and 2 deletions
|
|
@ -2224,10 +2224,14 @@ class CustomStreamWrapper:
|
|||
429 (rate-limit) is explicitly exempted from the 4xx filter because
|
||||
it is transient and the Router should switch to another model group.
|
||||
"""
|
||||
self._restore_consumer_correlation_context()
|
||||
from litellm.exceptions import MidStreamFallbackError
|
||||
|
||||
# Map to OpenAI exception format
|
||||
# Map to OpenAI exception format. Some providers' mappers (e.g.
|
||||
# _map_anthropic_exception, _map_aleph_alpha_exception) synchronously
|
||||
# log a debug diagnostic (the raw status code) as part of mapping -
|
||||
# restore the consumer's outer context only after this completes, so
|
||||
# that diagnostic log line still carries the failing stream's own
|
||||
# trace_id/session_id instead of the consumer's (or an empty one).
|
||||
if isinstance(e, OpenAIError):
|
||||
mapped_exception: Exception = e
|
||||
else:
|
||||
|
|
@ -2241,6 +2245,7 @@ class CustomStreamWrapper:
|
|||
)
|
||||
except Exception as mapping_error:
|
||||
mapped_exception = mapping_error
|
||||
self._restore_consumer_correlation_context()
|
||||
|
||||
def _normalize_status_code(exc: Exception) -> int | None:
|
||||
"""Best-effort status_code extraction."""
|
||||
|
|
|
|||
|
|
@ -3909,3 +3909,52 @@ async def test_stream_wrapper_aclose_restores_consumer_correlation_context():
|
|||
finally:
|
||||
trace_id_var.set("")
|
||||
session_id_var.set("")
|
||||
|
||||
|
||||
def test_handle_stream_fallback_error_restores_context_only_after_exception_mapping(monkeypatch):
|
||||
"""_map_anthropic_exception/_map_aleph_alpha_exception synchronously log a
|
||||
debug diagnostic (the raw status code) as part of exception_type()'s
|
||||
mapping. The consumer's outer context must not be restored until that
|
||||
mapping call returns, or the diagnostic log line would carry the outer
|
||||
(or empty) trace_id/session_id instead of the failing stream's own."""
|
||||
trace_id_var.set("outer-trace-fallback")
|
||||
session_id_var.set("outer-session-fallback")
|
||||
try:
|
||||
log_obj = Logging(
|
||||
model="claude-3-opus",
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
stream=True,
|
||||
call_type="completion",
|
||||
start_time=None,
|
||||
litellm_call_id="fallback-error-call",
|
||||
function_id="fn-fallback-error",
|
||||
kwargs={"litellm_session_id": "fallback-error-session"},
|
||||
)
|
||||
wrapper = CustomStreamWrapper(
|
||||
completion_stream=iter([]),
|
||||
model="claude-3-opus",
|
||||
custom_llm_provider="anthropic",
|
||||
logging_obj=log_obj,
|
||||
)
|
||||
|
||||
captured_ids = {}
|
||||
|
||||
def fake_exception_type(**kwargs):
|
||||
captured_ids["trace_id"] = trace_id_var.get()
|
||||
captured_ids["session_id"] = session_id_var.get()
|
||||
return ValueError("mapped boom")
|
||||
|
||||
monkeypatch.setattr("litellm.litellm_core_utils.streaming_handler.exception_type", fake_exception_type)
|
||||
|
||||
with pytest.raises(Exception):
|
||||
wrapper._handle_stream_fallback_error(RuntimeError("boom"))
|
||||
|
||||
# The mapper ran while the stream's own ids were still active.
|
||||
assert captured_ids["trace_id"] == log_obj.litellm_trace_id
|
||||
assert captured_ids["session_id"] == "fallback-error-session"
|
||||
# Restored to the consumer's outer context once mapping/raise completes.
|
||||
assert trace_id_var.get() == "outer-trace-fallback"
|
||||
assert session_id_var.get() == "outer-session-fallback"
|
||||
finally:
|
||||
trace_id_var.set("")
|
||||
session_id_var.set("")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue