Describe the bug
When an entrypoint generator yields an object that json.dumps cannot serialise, BedrockAgentCoreApp._safe_serialize_to_json_string (runtime/app.py line 898 in 1.22.0) tries convert_complex_objects and then falls back to json.dumps(str(obj)). convert_complex_objects (runtime/utils.py) handles Pydantic models, dataclasses, dicts, lists, tuples and sets but not bytes, so any event that contains binary data anywhere in its tree reaches the third fallback. The SSE data: line then carries a JSON string holding the Python repr of the dictionary, for example "{'result': {'type': 'agent_result', 'message': {... b'rsn_...'}}}", rather than a JSON object or an error.
The client cannot tell this apart from a legitimate string event, and it cannot recover the original payload from the repr. In our case a supervisor agent consuming a sub-agent's stream did event.get("error") on what was now a str and failed with AttributeError: 'str' object has no attribute 'get', turning every affected turn into a user-facing failure. Nothing was logged on the producing side, because the fallback succeeds.
To Reproduce
- Write a streaming entrypoint whose generator yields a dictionary containing a
bytes value somewhere inside it. A real-world source is the AgentResult.to_dict() from Strands when the model returns a reasoningContent.redactedContent block, which OpenAI GPT-5.6 Luna on Bedrock does after tool calls. Any other bytes value in a yielded event, such as image or document source.bytes from a tool result, takes the same path.
- Invoke the runtime and read the SSE stream.
- Observe that the event arrives as
data: "{'result': ...}" (a JSON string) instead of data: {"result": ...}.
Expected behavior
One of:
- binary values are converted to something JSON can carry (for example base64), or
- the event is replaced by an explicit error event, as
_stream_with_error_handling already does for exceptions, and a warning is logged.
Either way the consumer should never receive a Python repr as the payload.
Additional context
Describe the bug
When an entrypoint generator yields an object that
json.dumpscannot serialise,BedrockAgentCoreApp._safe_serialize_to_json_string(runtime/app.pyline 898 in 1.22.0) triesconvert_complex_objectsand then falls back tojson.dumps(str(obj)).convert_complex_objects(runtime/utils.py) handles Pydantic models, dataclasses, dicts, lists, tuples and sets but notbytes, so any event that contains binary data anywhere in its tree reaches the third fallback. The SSEdata:line then carries a JSON string holding the Python repr of the dictionary, for example"{'result': {'type': 'agent_result', 'message': {... b'rsn_...'}}}", rather than a JSON object or an error.The client cannot tell this apart from a legitimate string event, and it cannot recover the original payload from the repr. In our case a supervisor agent consuming a sub-agent's stream did
event.get("error")on what was now astrand failed withAttributeError: 'str' object has no attribute 'get', turning every affected turn into a user-facing failure. Nothing was logged on the producing side, because the fallback succeeds.To Reproduce
bytesvalue somewhere inside it. A real-world source is theAgentResult.to_dict()from Strands when the model returns areasoningContent.redactedContentblock, which OpenAI GPT-5.6 Luna on Bedrock does after tool calls. Any otherbytesvalue in a yielded event, such as image or documentsource.bytesfrom a tool result, takes the same path.data: "{'result': ...}"(a JSON string) instead ofdata: {"result": ...}.Expected behavior
One of:
_stream_with_error_handlingalready does for exceptions, and a warning is logged.Either way the consumer should never receive a Python repr as the payload.
Additional context
json.dumps(str(obj))itself fails, which it never does for a dictionary.AgentResult.to_dict()not being JSON-serialisable: [BUG] AgentResult.to_dict() is not JSON-serialisable when the message contains bytes (e.g. reasoningContent.redactedContent) strands-agents/harness-sdk#4167.