Skip to content

Bug: NonRecordingSpan crashes with 'NonRecordingSpan object has no attribute context' when observability exporter is enabled #166

Description

Description

When ENABLE_A365_OBSERVABILITY_EXPORTER=true is set and the token resolver returns None for the first turn (e.g., agentic auth not yet established), the OpenTelemetry TracerProvider returns a NonRecordingSpan instead of a real Span. Multiple locations in the A365 observability code access .context directly on the span object, which does not exist on NonRecordingSpan — only get_span_context() is available.

This causes the agent to crash on the very first scope creation with:

Exception caught : 'NonRecordingSpan' object has no attribute 'context'

Reproduction

  1. Deploy a Python agent with ENABLE_A365_OBSERVABILITY_EXPORTER=true
  2. Ensure the token resolver returns None on the first turn (e.g., agentic auth token not yet cached)
  3. Send the first message via Teams @mention
  4. The agent crashes with the above error

Verified against opentelemetry-api==1.33.1:

from opentelemetry.trace import NonRecordingSpan, SpanContext

s = NonRecordingSpan(SpanContext(0, 0, False))
print(hasattr(s, 'context'))          # False
print(hasattr(s, 'get_span_context')) # True
s.context                              # AttributeError
s.get_span_context()                   # Works correctly

Affected Files

File Lines Pattern
src/microsoft/opentelemetry/a365/core/opentelemetry_scope.py 166, 272 self._span.context.span_id
src/microsoft/opentelemetry/a365/core/exporters/enriched_span.py 58 return self._span.context
src/microsoft/opentelemetry/a365/core/exporters/agent365_exporter.py 463 ctx = sp.context

Root Cause

The Span interface in opentelemetry-api defines get_span_context() as the public method. The .context attribute is only available on the concrete ReadableSpan / recording span implementations but not on NonRecordingSpan. The A365 code uses .context (the attribute) instead of get_span_context() (the interface method), which works for recording spans but fails for non-recording spans.

Suggested Fix

Replace all span.context attribute accesses with span.get_span_context():

# Before (broken with NonRecordingSpan):
span_id = f"{self._span.context.span_id:016x}" if self._span.context else "unknown"

# After (safe for all span types):
sc = self._span.get_span_context()
span_id = f"{sc.span_id:016x}" if sc else "unknown"

Apply the same pattern to enriched_span.py and agent365_exporter.py.

Workaround

Set ENABLE_A365_OBSERVABILITY_EXPORTER=false and redeploy.

Environment

  • opentelemetry-api version: 1.33.1
  • Python 3.11+
  • Agent deployed to Azure App Service with Teams channel

Related

The same bug exists in microsoft/Agent365-python (same code vendored under libraries/microsoft-agents-a365-observability-core/). A parallel issue will be filed there.

/cc Hector Hernandez (@hectorhdzg) Nikhil Navakiran (@nikhilNava) PengF (@fpfp100)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions