Skip to content

fix(tracing): stop fabricating EndTime for live spans#1806

Merged
JosephMar merged 2 commits into
mainfrom
fix/live-span-null-endtime
Jul 9, 2026
Merged

fix(tracing): stop fabricating EndTime for live spans#1806
JosephMar merged 2 commits into
mainfrom
fix/live-span-null-endtime

Conversation

@JosephMar

Copy link
Copy Markdown
Member

Summary

otel_span_to_uipath_span stamps EndTime = datetime.now() when converting a span that hasn't ended (otel_span.end_time is None), and the UiPathSpan dataclass defaults end_time to now() too. A live OTel span legitimately has end_time = None — the fallback is a local invention, not a framework requirement.

Why it matters: the fabricated EndTime makes in-progress upserts (the upsert_span RUNNING → OK lifecycle) indistinguishable from ended spans everywhere downstream:

  • The LLMOps traceview UI renders phantom sub-millisecond durations for open snapshots.
  • The Insights OTLP export's unclosed-span filter (which drops EndTime == null spans) never fires, so every v3-ingested span reaches customer OTLP endpoints twice — once as an open snapshot with a ~0–1ms duration and no status, once as the real terminal span.

Verified against LLMOps alpha Table Storage: open writes arrive with EndTime == UpdatedAt ≈ StartTime (e.g. an agentRun open write with Start .456 / End .457 / Status Unset followed 33s later by the terminal Ok write).

Change

  • Live spans convert with end_time = None, serialized as "EndTime": null. The LLMOps v3 ingest contract accepts null (SpanV3Req.EndTime is DateTime?), and storage/UI already handle unclosed spans on the v2 path.
  • UiPathSpan.end_time becomes Optional[str] = None (the eval runtime already passes data.get("end_time") — i.e. possibly None — into this field today).
  • Ended spans are unchanged.

Not addressed here (follow-up worth considering)

Some open-write call sites don't pass status_override=SpanStatus.RUNNING, so open snapshots land with Unset status (observed on Agents-source spans) instead of Running. Marking all open upserts RUNNING would make in-progress state explicit rather than inferred. Insights-side interim handling: UiPath/Insights-monitoring#3041.

Tests

packages/uipath-platform: full suite 1434 passed, 7 skipped (pre-existing credential-gated skips). Two new tests pin the contract: live span → end_time is None / to_dict()["EndTime"] is None; ended span keeps its real end time.

🤖 Generated with Claude Code

otel_span_to_uipath_span stamped EndTime=now() when converting a span that
has not ended (otel_span.end_time is None), and the UiPathSpan dataclass
defaulted end_time to now() as well. This makes in-progress upserts (the
upsert_span RUNNING -> OK lifecycle) indistinguishable from ended spans
downstream: the LLMOps traceview UI renders phantom sub-millisecond
durations for open snapshots, and the Insights OTLP export's unclosed-span
filter never fires — so every v3-ingested span reaches customer OTLP
endpoints twice (open + terminal snapshot). Verified against LLMOps alpha
storage: open writes arrive with EndTime == UpdatedAt ≈ StartTime.

Live spans now convert with end_time=None, serialized as EndTime: null —
the LLMOps v3 ingest contract (SpanV3Req.EndTime) is nullable, and OTel
itself models unfinished spans with end_time=None; the fallback was a
local invention, not a framework requirement. Ended spans are unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 9, 2026 16:31
@github-actions github-actions Bot added test:uipath-langchain Triggers tests in the uipath-langchain-python repository test:uipath-integrations labels Jul 9, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes span conversion/serialization so in-progress (live) OpenTelemetry spans are not treated as ended spans by downstream UiPath tracing consumers. It preserves end_time=None for live spans so "EndTime": null is emitted, avoiding fabricated durations and preventing duplicate exports in pipelines that rely on EndTime == null to detect unclosed spans.

Changes:

  • Update UiPathSpan.end_time to be Optional[str] = None so “not ended” is representable and serializes as JSON null.
  • Update otel_span_to_uipath_span to preserve end_time=None when the OTEL span has not ended (instead of stamping datetime.now()).
  • Add tests covering live-span (EndTime is None) and ended-span (real end time preserved) conversion behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
packages/uipath-platform/src/uipath/platform/common/_span_utils.py Stops fabricating end times for live spans and makes UiPathSpan.end_time nullable so EndTime: null can be emitted.
packages/uipath-platform/tests/services/test_span_utils.py Adds regression tests ensuring live spans convert with end_time=None and ended spans retain their actual end time.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Required by check-versions since 0.2.5 is already published on PyPI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

🚨 Heads up: uipath-integrations cross-tests are FAILING 🚨

Your changes may break one or more integrations in uipath-integrations-python:

  • uipath-openai-agents
  • uipath-google-adk
  • uipath-agent-framework
  • uipath-llamaindex
  • uipath-pydantic-ai

⚠️ These checks are NOT enforced by branch protection rules. Please review the failures before merging.

🔍 Inspect the failed run →

@sonarqubecloud

sonarqubecloud Bot commented Jul 9, 2026

Copy link
Copy Markdown

@JosephMar JosephMar merged commit 62081f5 into main Jul 9, 2026
163 of 165 checks passed
@JosephMar JosephMar deleted the fix/live-span-null-endtime branch July 9, 2026 19:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test:uipath-integrations test:uipath-langchain Triggers tests in the uipath-langchain-python repository

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants