Skip to content

fix(tracing): release the span scope when a generator is closed - #4233

Merged
seratch merged 2 commits into
openai:mainfrom
adityasingh2400:fix-span-generator-exit-scope
Aug 6, 2026
Merged

fix(tracing): release the span scope when a generator is closed#4233
seratch merged 2 commits into
openai:mainfrom
adityasingh2400:fix-span-generator-exit-scope

Conversation

@adityasingh2400

@adityasingh2400 adityasingh2400 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

SpanImpl.__exit__ and NoOpSpan.__exit__ passed reset_current=False whenever the with block unwound on GeneratorExit, so closing a generator from the task that advanced it left the ended span current and nested every span opened afterwards under it. The token saved by start is still valid on that path, because the generator body resumes in the caller's own context, so the reset both can and should run.

#4221 made exactly this correction at the trace level for TraceImpl, ReattachedTrace, and NoOpTrace, and the span level was left behind. This restores the pairing, with the tolerance narrowed to the reset itself: finish runs without the reset, and only Scope.reset_current_span is guarded, since that is the one call that can raise on a foreign token. Guarding the whole finish would swallow a processor that raises ValueError from on_span_end, which propagates on main today, so that would be a new regression rather than a fix.

Fail-before evidence, in both directions. With src/agents/tracing/spans.py reverted to main and the new tests kept, test_generator_close_in_the_same_task_releases_the_span_scope fails for both parameters with assert <agents.tracing.spans.SpanImpl object at 0x...> is None, giving 2 failed and 5 passed. With the helper written as a single try around the whole finish call instead, test_generator_close_surfaces_processor_failure fails with Failed: DID NOT RAISE <class 'ValueError'>. The committed form gives 7 passed, and the full suite plus make lint and make typecheck are green.

SpanImpl.__exit__ and NoOpSpan.__exit__ passed reset_current=False whenever the
with block unwound on GeneratorExit, so closing a generator from the task that
advanced it left the ended span current and nested every later span under it.
The token saved by start is still valid on that path because the body resumes in
the caller's own context, so the reset both can and should run. openai#4221 made the
same correction for TraceImpl, ReattachedTrace, and NoOpTrace, and this brings
the span level back in line with it by reusing that fix's shape: reset normally,
and tolerate only the cross-context ValueError that an abandoned generator
finalized from another task cannot avoid.
Wrapping the whole finish call in except ValueError would swallow a processor
that raises ValueError from on_span_end, drop the saved token, and leave the
finished span current for everything that ran afterwards. On main that failure
propagates, because the GeneratorExit path passes reset_current=False and never
guards the call, so catching it would be a new regression rather than a fix.
Run finish without the reset, then guard only Scope.reset_current_span, which
is the single call that can raise on a foreign token.

@seratch seratch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this addresses the concern. _finish_on_generator_exit now calls finish(reset_current=False) before handling the token and scopes the ValueError suppression to Scope.reset_current_span, so processor failures still propagate instead of being mistaken for foreign-context resets. The new regression exercises that exact path, while the existing tests retain same-task, cross-task, and explicit wrong-context coverage.

I do not see any further code changes needed. The latest CI run is still in progress, with seven checks passing and no failures at the time of review.

@seratch
seratch enabled auto-merge (squash) August 6, 2026 00:00
@seratch seratch added this to the 0.20.x milestone Aug 6, 2026
@seratch
seratch merged commit 141f599 into openai:main Aug 6, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants