Skip to content

Conversation

@alexander-alderman-webb
Copy link
Contributor

@alexander-alderman-webb alexander-alderman-webb commented Dec 1, 2025

Description

With #5165 we have a handle on the agent invocation span, as the span is now attached to the context wrapper returned from the AgentRunner.run() method.

Exceptions of type AgentsException are now caught on AgentRunner.run() instead of AgentRunner._run_single_turn(), because openai-agents attaches the context wrapper to these exceptions in the method.

Removing sentry_sdk.get_current_span() avoids double exit scenarios when the active span is not an agent invocation span. This is the case when the asyncio integration is used.

Previously, the script below results in a double span exit unhandled exception.

import asyncio

from unittest import mock

import agents
from agents import Agent, Runner

import sentry_sdk
from sentry_sdk.integrations.openai_agents import OpenAIAgentsIntegration
from sentry_sdk.integrations.asyncio import AsyncioIntegration

async def main():
    with mock.patch(
        "agents.models.openai_responses.OpenAIResponsesModel.get_response"
    ) as mock_get_response:
        mock_get_response.side_effect = Exception("Model Error")

        sentry_sdk.init(
            integrations=[OpenAIAgentsIntegration(), AsyncioIntegration()],
            traces_sample_rate=1.0,
            debug=True
        )

        agent = Agent(
            name="Bug Reproduction Agent",
            instructions="You are a test agent. Always use the broken_tool.",
            model="gpt-4o-mini",
        )

        try:
            await Runner.run(
                agent, "Test input", # run_config=test_run_config
            )
        except Exception:
            pass

if __name__ == "__main__":
    asyncio.run(main())

Issues

Reminders

@alexander-alderman-webb alexander-alderman-webb marked this pull request as ready for review December 1, 2025 09:10
@alexander-alderman-webb alexander-alderman-webb requested a review from a team as a code owner December 1, 2025 09:10
@alexander-alderman-webb alexander-alderman-webb marked this pull request as draft December 1, 2025 09:59
@alexander-alderman-webb alexander-alderman-webb marked this pull request as ready for review December 1, 2025 10:24
@codecov
Copy link

codecov bot commented Dec 1, 2025

Codecov Report

❌ Patch coverage is 81.35593% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.87%. Comparing base (bc982ed) to head (ef3ddc6).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...y_sdk/integrations/openai_agents/patches/runner.py 72.72% 5 Missing and 1 partial ⚠️
sentry_sdk/integrations/openai_agents/utils.py 75.00% 0 Missing and 3 partials ⚠️
...dk/integrations/openai_agents/patches/agent_run.py 88.88% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@                                 Coverage Diff                                  @@
##           webb/store-span-on-openai-agents-context-wrapper    #5174      +/-   ##
====================================================================================
- Coverage                                             83.91%   83.87%   -0.05%     
====================================================================================
  Files                                                   181      181              
  Lines                                                 18342    18379      +37     
  Branches                                               3260     3267       +7     
====================================================================================
+ Hits                                                  15392    15415      +23     
- Misses                                                 1944     1956      +12     
- Partials                                               1006     1008       +2     
Files with missing lines Coverage Δ
...ntegrations/openai_agents/patches/error_tracing.py 62.06% <100.00%> (+2.06%) ⬆️
...y_sdk/integrations/openai_agents/spans/__init__.py 100.00% <100.00%> (ø)
...k/integrations/openai_agents/spans/invoke_agent.py 92.10% <100.00%> (+3.86%) ⬆️
...dk/integrations/openai_agents/patches/agent_run.py 84.61% <88.88%> (+1.80%) ⬆️
sentry_sdk/integrations/openai_agents/utils.py 88.54% <75.00%> (-1.94%) ⬇️
...y_sdk/integrations/openai_agents/patches/runner.py 82.85% <72.72%> (-12.60%) ⬇️

... and 3 files with indirect coverage changes

@alexander-alderman-webb alexander-alderman-webb marked this pull request as draft December 1, 2025 11:52
@alexander-alderman-webb alexander-alderman-webb marked this pull request as ready for review December 1, 2025 13:24
# Handled in _run_single_turn() patch.
raise exc.original from None
except Exception as exc:
# Invoke agent span is not finished in this case.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I could add a get_current_span() again in this case and we would never lose spans.

You also can't guarantee that the SDK does not crash if you try to exit a span you obtain with get_current_span(), so I decided the just drop the span for now.

Much of AgentRunner.run() that is not spent in _run_single_turn() is before the agent invocation span is created anyway. The only cases in which we lose a span is that any of the post-turn steps like output guardrails raise an exception that is not an AgentsException.

current_span = sentry_sdk.get_current_span()
if current_span is not None and current_span.timestamp is None:
current_span.__exit__(None, None, None)
context_wrapper = getattr(exc.run_data, "context_wrapper", None)
Copy link

Choose a reason for hiding this comment

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

Bug: AttributeError when accessing exc.run_data without checking existence

The code accesses exc.run_data.context_wrapper using getattr but doesn't first verify that exc has a run_data attribute. If AgentsException lacks a run_data attribute, accessing exc.run_data will raise an AttributeError before getattr is called. The code should use getattr(exc, "run_data", None) first to safely check for the attribute's existence, consistent with the defensive pattern used for context_wrapper.

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In practice it's always set as AgentRunner.run() has a big try-except as the top-level.

_record_exception_on_span(span, exc)
end_invoke_agent_span(context_wrapper, agent)

raise _SingleTurnException(exc)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I created _SingleTurnException to avoid calling capture_exception() twice.

Otherwise, exceptions raised in _run_single_turn() that are not of type AgentsException would be captured in both run() and _run_single_turn().

Base automatically changed from webb/store-span-on-openai-agents-context-wrapper to master December 1, 2025 16:19
_capture_exception(exc)
raise exc from None

end_invoke_agent_span(run_result.context_wrapper, agent)
Copy link

Choose a reason for hiding this comment

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

Bug: run_result.context_wrapper is accessed directly without defensive checking, risking an AttributeError if the attribute is missing.
Severity: CRITICAL | Confidence: High

🔍 Detailed Analysis

Line 66 in runner.py directly accesses run_result.context_wrapper without checking if the attribute exists. If the RunResult object returned by agents.Runner.run() lacks a context_wrapper attribute, an AttributeError will be raised, causing an application crash. This contrasts with the exception handling path (lines 42-45), which defensively uses getattr(exc.run_data, "context_wrapper", None).

💡 Suggested Fix

Replace direct access run_result.context_wrapper with getattr(run_result, "context_wrapper", None) to safely retrieve the attribute, similar to the exception path.

🤖 Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: sentry_sdk/integrations/openai_agents/patches/runner.py#L66

Potential issue: Line 66 in `runner.py` directly accesses `run_result.context_wrapper`
without checking if the attribute exists. If the `RunResult` object returned by
`agents.Runner.run()` lacks a `context_wrapper` attribute, an `AttributeError` will be
raised, causing an application crash. This contrasts with the exception handling path
(lines 42-45), which defensively uses `getattr(exc.run_data, "context_wrapper", None)`.

Did we get this right? 👍 / 👎 to inform future reviews.
Reference ID: 4596996

Copy link
Contributor Author

Choose a reason for hiding this comment

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

duplicate of #5174 (comment)

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