Skip to content

fix(metrics): convert list attribute values to tuples for aggregation key#5303

Open
grvmishra788 wants to merge 4 commits into
open-telemetry:mainfrom
grvmishra788:worktree-issue-3750
Open

fix(metrics): convert list attribute values to tuples for aggregation key#5303
grvmishra788 wants to merge 4 commits into
open-telemetry:mainfrom
grvmishra788:worktree-issue-3750

Conversation

@grvmishra788

@grvmishra788 grvmishra788 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Description

When users pass list-valued attributes to metrics (e.g. {"tags": ["a", "b"]}), the SDK crashes with TypeError: unhashable type: 'list'. This happens because consume_measurement() builds an aggregation key using frozenset(attributes.items()), and lists are not hashable.

The Attributes type in opentelemetry-api explicitly allows Sequence values, including lists. The trace API already handles this correctly through _clean_attribute(), but the metrics path bypasses that function entirely.

Before: Passing a list as an attribute value raises a TypeError and drops the measurement.

After: Non-string, non-bytes sequence values are converted to tuples when frozenset() fails. Measurements with [1, 2] and (1, 2) for the same attribute now produce the same aggregation key, which is consistent with how the rest of the SDK treats sequences.

The fix uses a try-first approach: it attempts frozenset(attributes.items()) directly, and only falls back to the conversion loop if a TypeError is raised. This keeps the hot path (all scalar/tuple attributes) at zero overhead. Strings and bytes are explicitly excluded from conversion since they are technically sequences but should stay as-is.

Fixes #3750

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

  • Four new unit tests cover the fix
  • tox -e lint-opentelemetry-sdk
  • tox -e py314-test-opentelemetry-sdk -- -ra

Does This PR Require a Contrib Repo Change?

  • No.

Checklist:

  • Followed the style guidelines of this project
  • Changelogs have been updated
  • Unit tests have been added
  • Documentation has been updated

Notes

Why try-first instead of always converting? As discussed in #3750, performance matters here because this code runs on every measurement. Benchmarking showed three approaches with very different overhead on the common case (all scalar attributes, 4 keys):

Approach Scalar overhead (ns/op) Notes
isinstance(Sequence) loop +2,210 ns ABC check is expensive
isinstance(list) loop +454 ns Only handles list, not all Sequence subclasses
try frozenset() first +6 ns Zero-cost happy path, pays ~1 us on TypeError fallback

The try-first approach wins clearly on the hot path. When lists are present, the exception + retry costs about 3-4 us per measurement, but that only happens once per unique attribute set (subsequent measurements hit the aggr_key in self._attributes_aggregation cache).

Why not use _clean_attribute()? The API layer's _clean_attribute() function does similar tuple conversion, but it also validates types and logs warnings. Calling it here would add overhead on every measurement for validation that should have already happened at the API boundary.

grvmishra788 added a commit to grvmishra788/opentelemetry-python that referenced this pull request Jun 15, 2026
@grvmishra788 grvmishra788 force-pushed the worktree-issue-3750 branch from e4cf25c to 0e563e0 Compare June 15, 2026 17:39
@grvmishra788 grvmishra788 marked this pull request as ready for review June 15, 2026 17:49
@grvmishra788 grvmishra788 requested a review from a team as a code owner June 15, 2026 17:49
@DylanRussell

Copy link
Copy Markdown
Contributor

Hey I also came across this and am proposing a change to the same code in #5266 -- can you take a look and see if my approach would work for you too ? Feel free to add comments to that PR...

@herin049

herin049 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Can you either run/modify the existing benchmarks we have for metrics and compare the performance before and after introducing these changes?

Also, we may want to close/defer this work given that most of this will likely be addressed by #5266 and/or related work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Metric attributes does not accept all types of sequences

3 participants