open-telemetry / open-telemetry/opentelemetry-python
Span.set_status: a bare Status(ERROR) replaces an existing Status(ERROR, description) and drops the description
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 2.6k
- Forks
- 1k
- Avg merge
- 4d 15h
- Merged PRs (30d)
- 19
Description
Describe your environment
opentelemetry-sdk 1.44.0, CPython 3.11. Also present at main (opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py, Span.set_status).
What happened?
set_status guards two cases when it is handed a Status instance: it returns early if the span is already OK, and it returns early if the incoming status is UNSET. Nothing guards a second ERROR overwriting a first one, so self._status = status runs unconditionally and a bare Status(StatusCode.ERROR) with no description silently replaces Status(StatusCode.ERROR, "..."). The status code is unchanged, so nothing looks wrong; only the description disappears.
This is reachable without anyone doing something odd. A library sets a specific error on a span, and later generic error handling, exception bookkeeping or an instrumentation helper sets a plain ERROR on the same span. The specific message is the one that had diagnostic value, and it is the one that is lost.
Steps to reproduce
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.trace import Status, StatusCode
span = TracerProvider().get_tracer(__name__).start_span("demo")
span.set_status(Status(StatusCode.ERROR, "connection refused to db-1"))
span.set_status(Status(StatusCode.ERROR))
print(span.status.description)
What did you expect to see?
connection refused to db-1.
What did you see instead?
None.
Suggested fix
In the isinstance(status, Status) branch, decline the assignment when the incoming status carries no description and the existing status has the same code and does have one. That keeps the first, more specific description without changing the status code, and it leaves every other transition alone, including a genuine re-description of an existing error.
It is a small change and I have it written, so a PR will follow this issue rather than wait on agreement. If maintainers would rather the precedence sat somewhere else, or would rather it not change at all, say so there and I will rework or close it.
Additional context
This surfaced from open-telemetry/opentelemetry-python-contrib#4769, where I first tried to handle it in the shared HTTP semconv helper by reading span.status before setting it. @herin049 pointed out, correctly, that the trace API does not expose a readable status on Span at all, only the SDK's ReadableSpan does, so that fix depended on an implementation detail and put precedence logic in two places that could disagree. Raising it here instead, where set_status already owns precedence.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read opentelemetry-sdk/src/opentelemetry/sdk/trace/init.py, focusing on Span.set_status and its isinstance(status, Status) branch. Run the reproduction with a described ERROR followed by a bare ERROR, then verify that the existing description remains while other status transitions are unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- observability-sre
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 85/100