Skip to content

A bytes-valued Resource attribute breaks every OTLP encoder - #5577

Open
dwin-gharibi wants to merge 2 commits into
open-telemetry:mainfrom
dwin-gharibi:fix/resource-bytes-attribute-hashing
Open

A bytes-valued Resource attribute breaks every OTLP encoder#5577
dwin-gharibi wants to merge 2 commits into
open-telemetry:mainfrom
dwin-gharibi:fix/resource-bytes-attribute-hashing

Conversation

@dwin-gharibi

Copy link
Copy Markdown

Closes #5576.

Description

Resource.__hash__ is implemented as hash(json.dumps(attributes, sort_keys=True)). types.AnyValue now includes bytes, which json.dumps refuses, so hashing a Resource that carries any bytes attribute raises TypeError.

Every OTLP encoder uses the Resource as a dictionary key to group telemetry, so the failure lands squarely in the export path for all three signals.

Root cause

opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py:256. __hash__ derives its value by JSON-serialising the attributes, and to_json at line 258 has the same problem. Neither passes a default handler, so any value outside JSON's native type set aborts the call.

Approach

Add a _json_default handler used by both __hash__ and to_json that renders bytes/bytearray as hex and falls back to str for anything else unexpected.

Rendering b"\x01" and the string "01" identically means the two Resources hash alike, but Resource.__eq__ still distinguishes them, so dictionary lookups stay correct - a hash collision is a performance detail, not a correctness one.

Deliberately minimal. Deriving a hash by serialising the entire attribute set on every call is wasteful for something used as a dictionary key in the export hot path, and a canonical-tuple hash would be a better long-term shape, but that is a larger change than this defect warrants.

Files changed

  • opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py
  • opentelemetry-sdk/tests/resources/test_resource_bytes_attributes.py
  • .changelog/5563.fixed

Testing

A dedicated module covers the object contract - hashable, usable as a dict key, to_json emits valid JSON, equal resources hash equally, differing bytes hash differently, and a bytes value stays distinct from its hex string - plus the full encode path for spans, metrics and logs, since the original failure only became visible at export.

Eight of the nine fail before the change.

Result: 864 passed in opentelemetry-sdk (855 baseline plus 9 new), 20 passed in opentelemetry-exporter-otlp-proto-common.

Risk / compatibility

to_json output changes only for resources that previously could not be serialised at all. No existing behaviour is altered for resources whose attributes are JSON-native.

`bytes` is a valid attribute value type, and every OTLP encoder groups
telemetry by using the Resource as a dict key. Assert that such a Resource
stays hashable, usable as a dict key and serialisable, and that the span,
metric and log export paths all survive it.

These tests fail with "TypeError: Object of type bytes is not JSON
serializable" against the current implementation.
`Resource.__hash__` and `to_json` serialise the attributes with `json.dumps`.
`types.AnyValue` admits `bytes`, which `json.dumps` refuses, so hashing a
Resource that carries any bytes attribute raises TypeError.

Every OTLP encoder groups telemetry by using the Resource as a dictionary key,
so the failure lands in the export path for all three signals. Under
`BatchSpanProcessor` the exception is swallowed by the processor's broad
exception handling, turning it into a permanent silent export failure rather
than a visible crash.

Give both call sites a `default` that renders bytes as hex. `__eq__` still
distinguishes b"\x01" from the string "01", so the resulting hash collision is
harmless, and `to_json` stays valid JSON.
Copilot AI lite review requested due to automatic review settings August 23, 2026 17:10
@dwin-gharibi
dwin-gharibi requested a review from a team as a code owner August 23, 2026 17:10

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@opentelemetry-pr-dashboard

Copy link
Copy Markdown

Pull request dashboard status

Waiting on reviewers · refreshed 2026-08-23 17:11 UTC

Review the latest changes.

Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Anything look wrong? Report it with what you expected; it helps us improve the dashboard.

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.

A bytes-valued Resource attribute breaks every OTLP encoder

2 participants