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
_TracedStream.__anext__ (introduced in #272) wraps await self._inner.__anext__() in with use_span(self._span, end_on_exit=False):. The use_span context manager attaches a context token on enter and detaches on exit. When the awaited inner __anext__ suspends and resumes in a different asyncio Context, the detach raises:
ValueError: <Token var=<ContextVar name='current_context' default={} at 0x...> at 0x...> was created in a different Context
OTel logs this as "Failed to detach context" and a full traceback. Doesn't break functionality (spans + metrics still flow correctly), but produces noisy logs — observed ~19 occurrences during a single FastAPI chat-stream session.
Reproducer
Run a _TracedStream from a FastAPI streaming endpoint where the route handler is an async generator that yields chunks consumed by StreamingResponse. The asyncio task context the consumer runs in is different from the one that originally attached the span context inside __anext__.
Stack trace (truncated):
Failed to detach context
Traceback (most recent call last):
File ".../opentelemetry/context/__init__.py", line 155, in detach
_RUNTIME_CONTEXT.detach(token)
File ".../opentelemetry/context/contextvars_context.py", line 53, in detach
self._current_context.reset(token)
ValueError: <Token var=<ContextVar name='current_context' default={} at 0x...> at 0x...> was created in a different Context
Why it matters
19 stack traces per chat session pollute logs in production-equivalent setups (Cloud Run, etc.).
Token-mismatch is a known OTel pattern when context-attach/detach straddles asyncio task boundaries; it's a real bug, not a benign warning.
Inside _TracedStream.__anext__, instead of with use_span(self._span, end_on_exit=False): wrapping await self._inner.__anext__(), attach the span as the current span explicitly via trace.set_span_in_context(span) + context.attach(ctx) only for the duration of the synchronous span-attribute mutation (TTFC, etc.) — not across the await.
Or: drop use_span(... end_on_exit=False) entirely. The _TracedStream already manages span lifecycle via _finalize; making the span "current" during the inner __anext__ is what triggers the regression. Most consumers rely on parent-via-trace_id rather than parent-via-current-span.
Discovered while validating chat-backend metric export (no impact on the metric work itself; metrics + spans both reach Cloud Monitoring/Trace correctly).
Summary
_TracedStream.__anext__(introduced in #272) wrapsawait self._inner.__anext__()inwith use_span(self._span, end_on_exit=False):. Theuse_spancontext manager attaches a context token on enter and detaches on exit. When the awaited inner__anext__suspends and resumes in a different asyncio Context, the detach raises:OTel logs this as "Failed to detach context" and a full traceback. Doesn't break functionality (spans + metrics still flow correctly), but produces noisy logs — observed ~19 occurrences during a single FastAPI chat-stream session.
Reproducer
Run a
_TracedStreamfrom a FastAPI streaming endpoint where the route handler is an async generator that yields chunks consumed byStreamingResponse. The asyncio task context the consumer runs in is different from the one that originally attached the span context inside__anext__.Stack trace (truncated):
Why it matters
with-style context-attach across async-yield boundaries.Suggested fix
Inside
_TracedStream.__anext__, instead ofwith use_span(self._span, end_on_exit=False):wrappingawait self._inner.__anext__(), attach the span as the current span explicitly viatrace.set_span_in_context(span)+context.attach(ctx)only for the duration of the synchronous span-attribute mutation (TTFC, etc.) — not across theawait.Or: drop
use_span(... end_on_exit=False)entirely. The_TracedStreamalready manages span lifecycle via_finalize; making the span "current" during the inner__anext__is what triggers the regression. Most consumers rely on parent-via-trace_id rather than parent-via-current-span.Discovered while validating chat-backend metric export (no impact on the metric work itself; metrics + spans both reach Cloud Monitoring/Trace correctly).