open-telemetry / open-telemetry/opentelemetry-python

Unguarded str()/repr() calls crash the app when an attribute key/value's __str__/__repr__ raises

Open
#5,597 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Python
Stars
2.6k
Forks
1k
Avg merge
4d 15h
Merged PRs (30d)
19

Description

Describe your environment

OS: Windows 11 (also reproduces on Linux — not platform-specific)
Python version: Python 3.11
SDK version: current main branch (unreleased)
API version: current main branch (unreleased)

What happened?

Three separate code paths use "best-effort stringify" as a fallback when
an attribute key/value, log exception message, or baggage entry isn't
already a primitive type. In all three, the str()/repr() call is
completely unguarded -- if the object's str or repr itself
raises an exception, that exception propagates straight out of the
telemetry call and crashes the calling application, instead of degrading
gracefully as documented.

  1. opentelemetry-api/src/opentelemetry/attributes/init.py,
    _clean_attribute_value(): the function's own docstring says an
    unstringifiable value "is replaced with None", but str(key)/
    str(value) are called with no try/except. Crashes
    span.set_attribute(...).

  2. opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/init.py,
    LoggingHandler._get_attributes(): calls str(value.args[0]) unguarded
    when translating a stdlib LogRecord's exc_info into OTel log
    attributes. Crashes the extremely common
    logger.exception(...) / logger.error(msg, exc_info=True) pattern.

  3. opentelemetry-api/src/opentelemetry/baggage/propagation/init.py,
    _encode_baggage_pairs(): calls str(key)/str(value) unguarded, crashing
    W3CBaggagePropagator.inject().

All three represent the same underlying problem: observability/telemetry
code should never crash the application it's monitoring, especially over
something as incidental as failing to format a debug string. A single
malformed or unusual object (a buggy custom repr, a flaky third-party
exception class, a corrupted data object) passed as a span attribute,
logged exception, or baggage value takes down the entire request/process.

I have a fix and regression tests ready for all three sites and will open
a PR referencing this issue.

Steps to Reproduce
from opentelemetry.sdk.trace import TracerProvider

provider = TracerProvider()
tracer = provider.get_tracer("t")

class Bad:
    def __repr__(self):
        raise RuntimeError("boom from __repr__")

with tracer.start_as_current_span("s") as span:
    span.set_attribute("bad", Bad())   # raises RuntimeError, uncaught

Also reproduces via the logging bridge:

import logging
from opentelemetry.sdk._logs import LoggingHandler, LoggerProvider

class BadArg:
    def __str__(self):
        raise RuntimeError("BadArg.__str__ blew up")

class BadException(Exception):
    pass

handler = LoggingHandler(logger_provider=LoggerProvider())
py_logger = logging.getLogger("repro")
py_logger.addHandler(handler)
py_logger.setLevel(logging.ERROR)

try:
    raise BadException(BadArg())
except Exception:
    py_logger.exception("something failed")   # raises RuntimeError, uncaught

And via baggage:

from opentelemetry.baggage.propagation import W3CBaggagePropagator
from opentelemetry.baggage import set_baggage

class BadValue:
    def __str__(self):
        raise RuntimeError("boom from baggage value __str__")

propagator = W3CBaggagePropagator()
ctx = set_baggage("bad_key", BadValue())
propagator.inject({}, context=ctx)   # raises RuntimeError, uncaught
Expected Result

None of the three calls above should crash. Per each function's own
documented/implied contract, an unstringifiable value should be dropped
or replaced with a placeholder, with a warning logged -- not propagate
the exception into the caller.

Actual Result

All three raise RuntimeError uncaught, crashing the calling code.

Additional context

Fix already submitted, bundling all three sites into one PR since they
share the same root cause and fix pattern.

Would you like to implement a fix?

Yes

Tip

React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it. Learn more here.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with _clean_attribute_value() in opentelemetry-api/src/opentelemetry/attributes/init.py, LoggingHandler._get_attributes() in opentelemetry-sdk/src/opentelemetry/sdk/_logs/_internal/init.py, and _encode_baggage_pairs() in opentelemetry-api/src/opentelemetry/baggage/propagation/init.py. Review the existing tests and add or run regression coverage for objects whose str or repr raises; done means attribute, logging, and baggage calls degrade as documented without propagating the formatting exception.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
observability-sre
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.