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

Open
#4,983 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature:tracing
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.