From 19de9894c288a1a4c8df6e307980852fc0de6e22 Mon Sep 17 00:00:00 2001 From: Praveen Ghuge Date: Fri, 17 Jul 2026 19:47:50 +0530 Subject: [PATCH] fix(mavvrik_focus): guard against malformed Tags JSON in token merge json.loads on the existing Tags value had no error handling; a malformed value would raise JSONDecodeError and abort the entire export window instead of just skipping that row's token merge. --- .../mavvrik_focus/mavvrik_focus_logger.py | 5 ++++- .../mavvrik_focus/test_mavvrik_focus_logger.py | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/litellm/integrations/mavvrik_focus/mavvrik_focus_logger.py b/litellm/integrations/mavvrik_focus/mavvrik_focus_logger.py index d61653c9559..83532f215e4 100644 --- a/litellm/integrations/mavvrik_focus/mavvrik_focus_logger.py +++ b/litellm/integrations/mavvrik_focus/mavvrik_focus_logger.py @@ -60,7 +60,10 @@ def _with_token_tags(data: pl.DataFrame, normalized: pl.DataFrame) -> pl.DataFra has_both = "prompt_tokens" in available and "completion_tokens" in available def _merge(tags_json: str, row: dict) -> str: - tags = json.loads(tags_json) if tags_json else {} + try: + tags = json.loads(tags_json) if tags_json else {} + except (TypeError, ValueError): + tags = {} for key in available: value = row.get(key) if value is not None: diff --git a/tests/test_litellm/integrations/mavvrik_focus/test_mavvrik_focus_logger.py b/tests/test_litellm/integrations/mavvrik_focus/test_mavvrik_focus_logger.py index 64890892915..c1b3e1fcedd 100644 --- a/tests/test_litellm/integrations/mavvrik_focus/test_mavvrik_focus_logger.py +++ b/tests/test_litellm/integrations/mavvrik_focus/test_mavvrik_focus_logger.py @@ -88,6 +88,20 @@ def test_with_token_tags_merges_prompt_and_completion_tokens() -> None: } +def test_with_token_tags_recovers_from_malformed_tags_json() -> None: + data = pl.DataFrame({"prompt_tokens": [57], "completion_tokens": [753]}) + normalized = pl.DataFrame({"Tags": ["not-valid-json"]}) + + result = _with_token_tags(data, normalized) + + tags = json.loads(result["Tags"][0]) + assert tags == { + "prompt_tokens": "57", + "completion_tokens": "753", + "total_tokens": "810", + } + + def test_with_token_tags_omits_total_when_only_one_token_column_present() -> None: data = pl.DataFrame({"prompt_tokens": [57]}) normalized = pl.DataFrame({"Tags": [json.dumps({"model": "azure/gpt-4o-mini"})]})