You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug Two related issues when using AgnoInstrumentor with async streaming (arun with stream=True, stream_events=True):
Failed to detach context errors on every streamed response. The arun_stream wrapper in _runs_wrapper.py:574 yields inside trace_api.use_span(span, end_on_exit=False). When the
async generator is closed (e.g. the consumer finishes iterating), GeneratorExit is raised during yield, which triggers use_span's exit → context.detach(token). By this point
the ContextVar token belongs to a different async context, so detach raises ValueError: <Token ...> was created in a different Context. This is a fundamental issue with OTEL
context propagation across async generator boundaries in Python. Should be related to[bug] Agno #2698
Teams inside Workflows create separate root traces instead of nesting. _get_team_span_context checks for _AGNO_PARENT_NODE_CONTEXT_KEY to decide whether a Team is top-level. If
no parent Team is found, it returns trace_api.set_span_in_context(trace_api.INVALID_SPAN), forcing a new root trace. However, when a Team runs as a step inside a Workflow, the
Workflow does not set _AGNO_PARENT_NODE_CONTEXT_KEY — it creates its own span via the workflow wrapper, not via the Team-specific context mechanism. As a result, the Team's
internal arun always appears as a separate top-level trace, disconnected from the Workflow trace.
Console shows ERROR - Failed to detach context with ValueError: <Token ...> was created in a different Context — triggered by GeneratorExit in arun_stream at
_runs_wrapper.py:574.
The exported spans show two separate traces: one for the Workflow (My_Workflow.arun → My_Team.aexecute_stream) and a second disconnected root trace for the Team's internal run
(My_Team.arun → Agent_A.arun → LLM call).
Expected behavior
No Failed to detach context errors during normal stream consumption.
All spans should be part of a single trace: My_Workflow.arun → My_Team.aexecute_stream → My_Team.arun → Agent_A.arun → LLM call.
Screenshots
(not actual screenshots because my use case is proprietary but those trees are based on the crafted example which I hand't run but guarantee that will work the same way)
Trace 1 (Workflow trace — Team's internal run is missing):
Workflow.arun
└── Team.aexecute_stream
└── Agent.aexecute_stream
└── Agent.arun
└── OpenAIChat.ainvoke_stream
Trace 2 (Team's internal run — disconnected from Workflow):
Team.arun
└── Team.arun
└── OpenAIChat.ainvoke_stream
Desktop (please complete the following information):
OS: macOS Darwin 25.3.0
Python: 3.12.11
agno: 2.5.3
openinference-instrumentation-agno: 0.1.28
opentelemetry-api / opentelemetry-sdk: 1.40.0
Additional context
The context detach error is also reported in #2698 — same root cause, same stack trace.
Root cause analysis for issue 2 (separate traces):
In _runs_wrapper.py, _get_team_span_context returns INVALID_SPAN context for any Team without a parent Team context:
def_get_team_span_context(agent_or_team):
ifnotisinstance(agent_or_team, Team):
returnNoneparent_team_node_id=context_api.get_value(_AGNO_PARENT_NODE_CONTEXT_KEY)
ifparent_team_node_idisNone:
returntrace_api.set_span_in_context(trace_api.INVALID_SPAN) # forces new rootreturnNone
This doesn't account for Teams running inside Workflows. The Workflow wrapper creates an active span, but doesn't set _AGNO_PARENT_NODE_CONTEXT_KEY. So the Team always sees None
and forces a new root trace.
Suggested fix: Also check for an active recording span before forcing a root:
def_get_team_span_context(agent_or_team):
ifnotisinstance(agent_or_team, Team):
returnNone# If there's already an active recording span (e.g. from a Workflow),# let the Team nest under it instead of forcing a new root tracecurrent_span=trace_api.get_current_span()
ifcurrent_spanandcurrent_span.is_recording():
returnNoneparent_team_node_id=context_api.get_value(_AGNO_PARENT_NODE_CONTEXT_KEY)
ifparent_team_node_idisNone:
returntrace_api.set_span_in_context(trace_api.INVALID_SPAN)
returnNone
I used claude code to generate this and hadn't thoroughly verified it but I hope it's correct or at least helpful.
Describe the bug
Two related issues when using AgnoInstrumentor with async streaming (arun with stream=True, stream_events=True):
async generator is closed (e.g. the consumer finishes iterating), GeneratorExit is raised during yield, which triggers use_span's exit → context.detach(token). By this point
the ContextVar token belongs to a different async context, so detach raises ValueError: <Token ...> was created in a different Context. This is a fundamental issue with OTEL
context propagation across async generator boundaries in Python. Should be related to [bug] Agno #2698
no parent Team is found, it returns trace_api.set_span_in_context(trace_api.INVALID_SPAN), forcing a new root trace. However, when a Team runs as a step inside a Workflow, the
Workflow does not set _AGNO_PARENT_NODE_CONTEXT_KEY — it creates its own span via the workflow wrapper, not via the Team-specific context mechanism. As a result, the Team's
internal arun always appears as a separate top-level trace, disconnected from the Workflow trace.
To Reproduce
Observed behavior
_runs_wrapper.py:574.
(My_Team.arun → Agent_A.arun → LLM call).
Expected behavior
Screenshots
(not actual screenshots because my use case is proprietary but those trees are based on the crafted example which I hand't run but guarantee that will work the same way)
Trace 1 (Workflow trace — Team's internal run is missing):
Workflow.arun
└── Team.aexecute_stream
└── Agent.aexecute_stream
└── Agent.arun
└── OpenAIChat.ainvoke_stream
Trace 2 (Team's internal run — disconnected from Workflow):
Team.arun
└── Team.arun
└── OpenAIChat.ainvoke_stream
Desktop (please complete the following information):
Additional context
The context detach error is also reported in #2698 — same root cause, same stack trace.
Root cause analysis for issue 2 (separate traces):
In _runs_wrapper.py, _get_team_span_context returns INVALID_SPAN context for any Team without a parent Team context:
This doesn't account for Teams running inside Workflows. The Workflow wrapper creates an active span, but doesn't set _AGNO_PARENT_NODE_CONTEXT_KEY. So the Team always sees None
and forces a new root trace.
Suggested fix: Also check for an active recording span before forcing a root:
I used claude code to generate this and hadn't thoroughly verified it but I hope it's correct or at least helpful.