From 197d7e4fa92f41759c6c8eb6a69bbae02e49afb3 Mon Sep 17 00:00:00 2001 From: Ambuj Upadhyay <34904987+lets-order-some-fries@users.noreply.github.com> Date: Sat, 15 Aug 2026 00:13:55 +0530 Subject: [PATCH] fix: tolerate RecursionError when decoding tool-call arguments json.loads raises RecursionError (not JSONDecodeError) on deeply nested input, which propagated and dropped the affected span. Fall back to the raw string like any other undecodable payload. Co-Authored-By: Claude Fable 5 --- litellm/integrations/datadog/datadog_llm_obs.py | 2 +- .../datadog/test_datadog_llm_obs_message_schema.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/litellm/integrations/datadog/datadog_llm_obs.py b/litellm/integrations/datadog/datadog_llm_obs.py index 664a0c75f80..8a85cca2254 100644 --- a/litellm/integrations/datadog/datadog_llm_obs.py +++ b/litellm/integrations/datadog/datadog_llm_obs.py @@ -57,7 +57,7 @@ def _parse_tool_call_arguments(raw: object) -> object: return raw try: return json.loads(raw) - except json.JSONDecodeError: + except (RecursionError, json.JSONDecodeError): return raw diff --git a/tests/test_litellm/integrations/datadog/test_datadog_llm_obs_message_schema.py b/tests/test_litellm/integrations/datadog/test_datadog_llm_obs_message_schema.py index 0661a79687d..bd91ad8a8fe 100644 --- a/tests/test_litellm/integrations/datadog/test_datadog_llm_obs_message_schema.py +++ b/tests/test_litellm/integrations/datadog/test_datadog_llm_obs_message_schema.py @@ -366,3 +366,14 @@ class TestDataDogLLMObsCacheTokenMetrics: assert "cache_write_input_tokens" not in metrics assert "non_cached_input_tokens" not in metrics assert metrics["input_tokens"] == 20.0 + + +def test_parse_tool_call_arguments_survives_deeply_nested_json(): + """A hostile/degenerate arguments string must fall back to the raw + string, not raise RecursionError and drop the span.""" + from litellm.integrations.datadog.datadog_llm_obs import ( + _parse_tool_call_arguments, + ) + + hostile = "[" * 50000 + assert _parse_tool_call_arguments(hostile) == hostile