openai / openai/openai-agents-python
BackendSpanExporter: one metadata or custom span value that isn't JSON serializable drops the whole export batch, including unrelated traces
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 29.6k
- Forks
- 4.8k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 123
Description
Describe the bug
BackendSpanExporter posts a whole batch of traces and spans in one request. If any one item in that batch has a value json can't encode, the request body can't be built, export() raises, and BatchTraceProcessor drops the entire batch. So one bad value in one run's trace_metadata also throws away every other trace and span that happened to be queued with it, including runs that had nothing wrong with them.
Things that trigger it: a uuid.UUID or datetime in RunConfig(trace_metadata=...), a datetime in custom_span(data=...), or a NaN or inf float (httpx2 encodes with allow_nan=False). It happens on the default OpenAI ingest endpoint and on custom endpoints.
Debug information
- Agents SDK version: 0.22.2 (also main at fbd2dbca)
- Python version: 3.14.3
- Operating system: macOS
- Model and model provider: none needed, the repro uses
ScriptedModel - Does the issue reproduce with the latest Agents SDK release? Yes
- Does the issue occur consistently or intermittently? Consistently
ERROR [non-fatal] Tracing exporter failed; dropping batch of 8 items
items received: 0 []
Calling the exporter directly shows the cause:
exporter.export([trace("x", metadata={"request_id": uuid.uuid4()})])
TypeError: Object of type UUID is not JSON serializable
Repro steps
The repro doesn't touch the network. httpx2.MockTransport stands in for the ingest endpoint.
import asyncio, json, uuid, logging
import httpx2
from agents import Agent, Runner, RunConfig
from agents.testing.model import ScriptedModel, assistant_message
from agents.tracing import set_trace_processors
from agents.tracing.processors import BackendSpanExporter, BatchTraceProcessor
logging.basicConfig(level=logging.ERROR, format="%(levelname)s %(message)s")
received = []
def handler(request):
received.extend(json.loads(request.content)["data"])
return httpx2.Response(200)
exporter = BackendSpanExporter(api_key="sk-fake") # default OpenAI ingest endpoint
exporter._client = httpx2.Client(transport=httpx2.MockTransport(handler))
processor = BatchTraceProcessor(exporter, schedule_delay=3600)
set_trace_processors([processor])
async def main():
agent = Agent(name="assistant", model=ScriptedModel([[assistant_message("hi")], [assistant_message("hi")]]))
await Runner.run(agent, "hello", run_config=RunConfig(workflow_name="run_A")) # nothing wrong with this run
await Runner.run(agent, "hello", run_config=RunConfig(
workflow_name="run_B", trace_metadata={"request_id": uuid.uuid4()}))
asyncio.run(main())
processor.force_flush()
print("items received:", len(received), [d.get("workflow_name") for d in received if d.get("object") == "trace"])
Expected behavior
run_A's trace and spans get exported no matter what's in run_B's metadata. At most, the value that can't be encoded gets dropped from run_B, and run_B's trace and spans still arrive.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with BackendSpanExporter.export() and BatchTraceProcessor, using the provided httpx2.MockTransport reproduction to observe how one non-serializable metadata or custom span value affects a batch. Done means unrelated traces and spans are exported, while the problematic value is dropped or otherwise handled without causing export() to raise; add coverage for UUID, datetime, NaN, and inf cases if the existing tests provide a suitable location.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- observability-sre
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100