🔴 Required Information
Describe the Bug:
When the upstream model returns malformed JSON in tool_call.function.arguments (truncated strings, unclosed objects, partial streams committed to the message), google.adk.models.lite_llm._message_to_generate_content_response calls json.loads(tool_call.function.arguments or "{}") without a guard and raises json.JSONDecodeError. The exception propagates out of LiteLLM response parsing — upstream of any tool or callback boundary — so the entire invocation aborts and the user sees a generic streaming-error message rather than a recoverable tool-call retry.
This is the same bug as the previously closed #5008. That issue was closed after the original reporter said the upgrade had resolved it for them; a subsequent commenter (@NerdSmith) noted it still reproduced on 1.32.0, but the issue was not reopened. The crash site is unchanged on main at v2.0.0 (src/google/adk/models/lite_llm.py around _message_to_generate_content_response, the args=json.loads(tool_call.function.arguments or "{}") line).
Steps to Reproduce:
- Install
google-adk==2.0.0 (or build from main) and litellm.
- Run any ADK flow that uses a LiteLLM-wrapped model and emits a function call.
- Cause the model to emit malformed JSON in
tool_call.function.arguments — easiest in a test by constructing the message directly (see Minimal Reproduction Code below).
- Observe
JSONDecodeError propagate out of _message_to_generate_content_response.
Expected Behavior:
ADK should treat malformed tool-argument JSON as a recoverable model error. Log a warning with the raw arguments and pass an empty dict (or equivalent) to the function-call Part so the downstream tool dispatch surfaces a structured bad_arguments-style error to the model. The agent loop survives and the model can retry with corrected JSON.
Observed Behavior:
File ".../google/adk/models/lite_llm.py", line 1730, in _message_to_generate_content_response
args=json.loads(tool_call.function.arguments or "{}"),
File "/usr/local/lib/python3.12/json/__init__.py", line 346, in loads
return _default_decoder.decode(s)
File "/usr/local/lib/python3.12/json/decoder.py", line 354, in raw_decode
obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 2 (char 1)
Environment Details:
- ADK Library Version:
2.0.0 (main, commit aa515125)
- Desktop OS: macOS 25.3.0 (also reproduced on Linux in Cloud Run staging)
- Python Version:
3.11.15 (also reproduced under 3.12)
Model Information:
🟡 Optional Information
Regression:
Filed as still-broken at 1.32.0 in the trailing comment on #5008, and confirmed still present at 2.0.0.
Logs:
See Observed Behavior above.
Additional Context:
The failure happens during LiteLLM response → ADK LlmResponse conversion, which sits upstream of before_tool_callback / after_tool_callback and the tool dispatch layer. So no callback-level mitigation is possible — the entire invocation aborts. From a production-operator perspective this is one of the harder ADK crashes to recover from: the trace lands in framework code, not user code, and the user-facing error is a generic stream failure with no information about the malformed tool call.
Minimal Reproduction Code:
from google.adk.models.lite_llm import _message_to_generate_content_response
from litellm import ChatCompletionAssistantMessage, ChatCompletionMessageToolCall
from litellm.types.utils import Function
message = ChatCompletionAssistantMessage(
role="assistant",
content=None,
tool_calls=[
ChatCompletionMessageToolCall(
type="function",
id="call_1",
function=Function(name="demo_tool", arguments='{"city":"unterminated'),
)
],
)
_message_to_generate_content_response(message) # raises json.JSONDecodeError
How often has this issue occurred?:
- Intermittently (<50%) — model-dependent, hits more often on long/streamed tool args under load.
I have a fix + unit tests ready as a PR: https://github.com/Ja-Crispy/adk-python/tree/fix-litellm-malformed-tool-args-json — happy to open it against this issue once it's triaged.
🔴 Required Information
Describe the Bug:
When the upstream model returns malformed JSON in
tool_call.function.arguments(truncated strings, unclosed objects, partial streams committed to the message),google.adk.models.lite_llm._message_to_generate_content_responsecallsjson.loads(tool_call.function.arguments or "{}")without a guard and raisesjson.JSONDecodeError. The exception propagates out of LiteLLM response parsing — upstream of any tool or callback boundary — so the entire invocation aborts and the user sees a generic streaming-error message rather than a recoverable tool-call retry.This is the same bug as the previously closed #5008. That issue was closed after the original reporter said the upgrade had resolved it for them; a subsequent commenter (@NerdSmith) noted it still reproduced on
1.32.0, but the issue was not reopened. The crash site is unchanged onmainatv2.0.0(src/google/adk/models/lite_llm.pyaround_message_to_generate_content_response, theargs=json.loads(tool_call.function.arguments or "{}")line).Steps to Reproduce:
google-adk==2.0.0(or build frommain) andlitellm.tool_call.function.arguments— easiest in a test by constructing the message directly (see Minimal Reproduction Code below).JSONDecodeErrorpropagate out of_message_to_generate_content_response.Expected Behavior:
ADK should treat malformed tool-argument JSON as a recoverable model error. Log a warning with the raw arguments and pass an empty dict (or equivalent) to the function-call
Partso the downstream tool dispatch surfaces a structuredbad_arguments-style error to the model. The agent loop survives and the model can retry with corrected JSON.Observed Behavior:
Environment Details:
2.0.0(main, commitaa515125)3.11.15(also reproduced under3.12)Model Information:
🟡 Optional Information
Regression:
Filed as still-broken at
1.32.0in the trailing comment on #5008, and confirmed still present at2.0.0.Logs:
See Observed Behavior above.
Additional Context:
The failure happens during LiteLLM response → ADK
LlmResponseconversion, which sits upstream ofbefore_tool_callback/after_tool_callbackand the tool dispatch layer. So no callback-level mitigation is possible — the entire invocation aborts. From a production-operator perspective this is one of the harder ADK crashes to recover from: the trace lands in framework code, not user code, and the user-facing error is a generic stream failure with no information about the malformed tool call.Minimal Reproduction Code:
How often has this issue occurred?:
I have a fix + unit tests ready as a PR: https://github.com/Ja-Crispy/adk-python/tree/fix-litellm-malformed-tool-args-json — happy to open it against this issue once it's triaged.