Skip to content

fix(httpx): record exception on span when an exception is raised#4396

Closed
RiyaChaturvedi37 wants to merge 1 commit intoopen-telemetry:mainfrom
RiyaChaturvedi37:fix/httpx-record-exception
Closed

fix(httpx): record exception on span when an exception is raised#4396
RiyaChaturvedi37 wants to merge 1 commit intoopen-telemetry:mainfrom
RiyaChaturvedi37:fix/httpx-record-exception

Conversation

@RiyaChaturvedi37
Copy link
Copy Markdown
Contributor

Closes #3914

Description

When an exception is raised during an httpx request, span.record_exception(exception)
was not being called explicitly. This meant that the full stack trace was not being
captured in the span events, causing missing stack traces in observability tools like Datadog.

This fix adds span.record_exception(exception) before re-raising the exception
in all 4 locations where exceptions are handled:

  • SyncOpenTelemetryTransport.__exit__
  • AsyncOpenTelemetryTransport.__aexit__
  • Sync instrumented client wrapper
  • Async instrumented client wrapper

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Copy link
Copy Markdown
Member

@MikeGoldsmith MikeGoldsmith left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution! However, I think there's a subtle issue with this approach.

start_as_current_span already handles exception recording automatically via its __exit__ method. When an exception escapes the with block, the context manager calls record_exception(exception, escaped=True) and set_status(ERROR) by default (controlled by the record_exception and set_status_on_exception parameters, both True by default).

Since the raise in all four locations is inside the with self._tracer.start_as_current_span(...) as span: block, the exception already propagates through __exit__, which records it. Adding an explicit record_exception call before the raise means the exception event is recorded twice — once explicitly with escaped=False, and once by the context manager with escaped=True.

The missing stack traces in Datadog are likely a Datadog-specific issue rather than a gap in this instrumentation. How are you exporting data to Datadog — via the OTLP exporter, or a Datadog-specific exporter? Some exporters don't forward span events, which would explain why the stack trace isn't appearing even though it's being recorded correctly by the instrumentation.

I'd suggest closing this PR and opening an issue/discussion on the Datadog side to understand why span events aren't surfacing.

@github-project-automation github-project-automation Bot moved this to Reviewed PRs that need fixes in Python PR digest Apr 9, 2026
@RiyaChaturvedi37
Copy link
Copy Markdown
Contributor Author

Thanks for the contribution! However, I think there's a subtle issue with this approach.

start_as_current_span already handles exception recording automatically via its __exit__ method. When an exception escapes the with block, the context manager calls record_exception(exception, escaped=True) and set_status(ERROR) by default (controlled by the record_exception and set_status_on_exception parameters, both True by default).

Since the raise in all four locations is inside the with self._tracer.start_as_current_span(...) as span: block, the exception already propagates through __exit__, which records it. Adding an explicit record_exception call before the raise means the exception event is recorded twice — once explicitly with escaped=False, and once by the context manager with escaped=True.

The missing stack traces in Datadog are likely a Datadog-specific issue rather than a gap in this instrumentation. How are you exporting data to Datadog — via the OTLP exporter, or a Datadog-specific exporter? Some exporters don't forward span events, which would explain why the stack trace isn't appearing even though it's being recorded correctly by the instrumentation.

I'd suggest closing this PR and opening an issue/discussion on the Datadog side to understand why span events aren't surfacing.

Thank you for the detailed explanation @MikeGoldsmith! You're absolutely right — I didn't realize that start_as_current_span already handles exception recording automatically via __exit__. I'll close this PR.

Regarding the Datadog issue, I'm using the OTLP exporter. I'll investigate on the Datadog side to understand why span events aren't surfacing there.

@github-project-automation github-project-automation Bot moved this from Reviewed PRs that need fixes to Done in Python PR digest Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

The stack trace is missing when an exception is thrown.

2 participants