traceloop / traceloop/openllmetry
π Bug Report: list-valued association properties crash metrics, and silently drop gen_ai.output.messages
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 7.4k
- Forks
- 1.1k
- Avg merge
- 8d 14h
- Merged PRs (30d)
- 2
Description
Which component is this bug for?
OpenAI Instrumentation
π Description
Description
When association properties (baggage set via set_association_properties() / OTel context, e.g. by the LangChain/LangGraph instrumentation's langgraph_triggers) contain a list value, metrics_common_attributes() in traceloop/sdk/tracing/tracing.py copies that value verbatim into the metrics attribute dict:
association_properties = get_value("association_properties")
if association_properties is not None:
for key, value in association_properties.items():
common_attributes[f"{SpanAttributes.TRACELOOP_ASSOCIATION_PROPERTIES}.{key}"] = value
This dict is registered as get_common_metrics_attributes for the OpenAI (and Anthropic/LiteLLM) instrumentor and merged into every Counter.record(...) call's attributes in _set_chat_metrics β _set_token_counter_metrics (opentelemetry-instrumentation-openai). OTel's metrics SDK requires attribute values to be scalar/hashable, since it uses frozenset(attributes.items()) to key aggregation. A list value causes an unhandled TypeError: unhashable type: 'list'.
Because this happens inside _handle_response in opentelemetry/instrumentation/openai/shared/chat_wrappers.py, which is wrapped by a single @dont_throw, the exception is silently swallowed (only a DEBUG log is emitted) and every response-side span attribute set after that point is lost β gen_ai.response.model, gen_ai.usage.*, and, most importantly, gen_ai.output.messages. Only gen_ai.input.messages (set earlier, before the response arrives) survives. Users see prompts/inputs in their traces but no completions/outputs, with no visible error unless they specifically enable DEBUG logging for opentelemetry.instrumentation.openai.
π Reproduction steps
- Install
traceloop-sdkwith LangGraph instrumentation enabled (opentelemetry-instrumentation-langchainpicks this up automatically) andopentelemetry-instrumentation-openai. - Run a LangGraph graph with more than one edge/trigger into a node so that LangGraph's callback sets
langgraph_triggers(alist[str]) as an association property/baggage value for that node's span β e.g. a node reachable via["branch:to:some_node"]. - Inside that LangGraph node, call
openai.AsyncOpenAI().chat.completions.create(...)(or the sync equivalent) withTraceloop.init()initialized normally (metrics enabled, the default). - Export/inspect the resulting
openai.chatspan's attributes.
Minimal repro sketch (no LangGraph dependency needed β directly setting the association property reproduces it):
from traceloop.sdk import Traceloop
from traceloop.sdk.tracing.tracing import set_association_properties
Traceloop.init(app_name="repro", disable_batch=True)
set_association_properties({"langgraph_triggers": ["branch:to:some_node"]})
# any chat.completions.create(...) call through an instrumented AsyncOpenAI/OpenAI client
Enabling logging.getLogger("opentelemetry.instrumentation.openai").setLevel(logging.DEBUG) surfaces:
OpenLLMetry failed to trace in _handle_response, error: Traceback (most recent call last):
...
File ".../opentelemetry/instrumentation/openai/shared/chat_wrappers.py", line 417, in _set_token_counter_metrics
token_counter.record(val, attributes=attributes_with_token_type)
...
File ".../opentelemetry/sdk/metrics/_internal/_view_instrument_match.py", line 101, in consume_measurement
aggr_key = frozenset(attributes.items())
TypeError: unhashable type: 'list'
π Expected behavior
- Association-property values that aren't valid OTel metric attribute types (i.e. anything other than
str,bool,int,float, or a homogeneous sequence of those) should be sanitized (e.g. JSON-encoded to a string, or dropped with a warning) before being merged intoget_common_metrics_attributes()'s output β mirroring how such values are already made safe when written to span attributes. - At minimum, a single malformed metrics attribute should never be able to silently abort span attribute capture for the rest of the response (
gen_ai.output.messages,gen_ai.response.model,gen_ai.usage.*). Metrics recording and span attribute setting are logically independent concerns and a failure in one should not cascade into the other.
π Actual Behavior with Screenshots
_set_chat_metrics(called near the top of_handle_response) raisesTypeError: unhashable type: 'list'when merging association properties containing a list value into metric attributes.- Because
_handle_responseis wrapped by a single@dont_throw, the exception aborts the rest of the function silently β no error is raised to the caller, and only a DEBUG-level log records it. - As a result,
gen_ai.output.messages,gen_ai.response.model, and allgen_ai.usage.*attributes are missing from the span, whilegen_ai.input.messages(set earlier, before the response) is present β making it look like only prompts are captured and completions are silently dropped, with no indication of why unless DEBUG logging happens to be enabled.
π€ Python Version
3.13
π Provide any additional context for the Bug.
No response
π Have you spent some time to check if this bug has been raised before?
- I checked and didn't find similar issue
Are you willing to submit PR?
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
Start in traceloop/sdk/tracing/tracing.py at metrics_common_attributes(), then read _handle_response and _set_token_counter_metrics in opentelemetry/instrumentation/openai/shared/chat_wrappers.py. Reproduce the list-valued association-property case with metrics enabled and verify that metric recording no longer prevents gen_ai.output.messages, response.model, and usage attributes from being captured.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- observability-sre
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 25/100