-
Notifications
You must be signed in to change notification settings - Fork 481
Description
Tracer Version(s)
4.3.1
Python Version(s)
3.14
Pip Version(s)
uv
Bug Report
The ddtrace Bedrock instrumentation crashes with a TypeError when processing tool use responses from AWS Bedrock. The issue occurs in ddtrace/llmobs/_integrations/utils.py in the get_final_message_converse_stream_message function.
The function attempts to parse tool_input with json.loads(), but AWS Bedrock sometimes returns tool inputs as already-parsed dict objects rather than JSON strings. This causes the instrumentation to fail with:
TypeError: the JSON object must be str, bytes or bytearray, not dict
Expected Behavior
The instrumentation should handle tool inputs regardless of whether they are:
- JSON strings (need parsing with
json.loads()) - Already-parsed dict objects (use directly)
Actual Behavior
The instrumentation crashes with TypeError when tool_input is a dict, breaking LLM observability and potentially disrupting the application flow.
Root Cause
In ddtrace/llmobs/_integrations/utils.py, the get_final_message_converse_stream_message function assumes tool_input is always a JSON string:
# Problematic code (approximate line 1448)
tool_input = tool_block.get("input")
tool_args = json.loads(tool_input) # Fails when tool_input is already a dictProposed Fix
Add type checking before attempting to parse:
tool_input = tool_block.get("input")
tool_args = {}
if isinstance(tool_input, dict):
# Already parsed - use directly
tool_args = tool_input
elif isinstance(tool_input, str):
# JSON string - parse it
try:
tool_args = json.loads(tool_input)
except (json.JSONDecodeError, ValueError):
# Invalid JSON - wrap in dict
tool_args = {"input": tool_input}
else:
# Unexpected type - convert to string
tool_args = {"input": str(tool_input)}Workaround
We've implemented a monkey-patch that wraps the problematic function with the type checking above. This is a temporary solution until the upstream fix is available.
Reproduction Code
- Set up AWS Bedrock with Claude model (Sonnet 4.5)
- Enable ddtrace LLM observability:
from ddtrace.llmobs import LLMObs LLMObs.enable( ml_app="my_app", api_key=os.getenv("DD_API_KEY"), site="datadoghq.com", agentless_enabled=True, integrations_enabled=True )
- Create an agent with tools using the Bedrock Converse API
- Invoke the agent with a prompt that triggers tool use
- Observe the TypeError when the agent attempts to use a tool
Error Logs
Traceback (most recent call last):
File "/usr/local/lib/python3.14/site-packages/strands/models/bedrock.py", line 770, in _stream
for chunk in response["stream"]:
File "/usr/local/lib/python3.14/site-packages/ddtrace/llmobs/_integrations/base_stream_handler.py", line 142, in __iter__
self._self_handler.process_chunk(chunk, self._self_stream_iter)
File "/usr/local/lib/python3.14/site-packages/ddtrace/contrib/internal/botocore/services/bedrock.py", line 92, in process_chunk
stream_processor.send(chunk)
File "/usr/local/lib/python3.14/site-packages/ddtrace/llmobs/_integrations/bedrock.py", line 325, in _converse_output_stream_processor
get_final_message_converse_stream_message(current_message, text_content_blocks, tool_content_blocks)
File "/usr/local/lib/python3.14/site-packages/ddtrace/llmobs/_integrations/utils.py", line 1448, in get_final_message_converse_stream_message
tool_args = json.loads(tool_input)
^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.14/json/__init__.py", line 345, in loads
raise TypeError(f'the JSON object must be str, bytes or bytearray, '
f'not {s.__class__.__name__}')
TypeError: the JSON object must be str, bytes or bytearray, not dictLibraries in Use
No response
Operating System
No response