Skip to content

fix(pymongo): decode bytes values instead of str()-ing them to avoid BytesWarning (#4782) - #7545

Open
DawnofGenX wants to merge 2 commits into
getsentry:masterfrom
DawnofGenX:fix/pymongo-bytes-collection-name
Open

DawnofGenX wants to merge 2 commits into
getsentry:masterfrom
DawnofGenX:fix/pymongo-bytes-collection-name

Conversation

@DawnofGenX

Copy link
Copy Markdown

What

Under python -b (BytesWarning mode), the PyMongo integration emits BytesWarning: str() on a bytes instance — see #4782. The flagged line (data["operation_ids"]["session"] = str(lsid) in 2.37.0, str(lsid_id) on master) stringifies the BSON logical session id, which is a bson.binary.Binary — a bytes subclass. Two stringify sites in CommandTracer.started() have the same problem:

  1. str(lsid_id) → session id becomes the literal string "b'...'" (plus BytesWarning under -b).
  2. json.dumps(command, default=str) → any raw bytes value in the command (e.g. a bytes collection name, as reported) goes through str() the same way.

How

  • Add _bytes_safe_str(): value.decode("utf-8", errors="replace") for bytes (and subclasses like Binary), plain str() otherwise. Undecodable bytes get U+FFFD replacements instead of an exception; nothing is caught or hidden — the actual stringification is fixed.
  • Use it at both sites above.

Tests

New regression tests in tests/integrations/pymongo/test_pymongo.py:

  • test_bytes_safe_str — helper unit test (decode, invalid-UTF-8 fallback, non-bytes passthrough).
  • test_bytes_lsid_does_not_raise_byteswarning (PII on/off) — drives CommandTracer.started() with a Binary lsid under warnings.simplefilter("error", BytesWarning) and asserts operation_ids.session is a clean decoded str, no b' prefix.
  • test_bytes_collection_name_in_query_does_not_raise_byteswarning — same with a bytes collection name in the command; asserts the span description contains test_collection, not b'test_collection'.

Verified locally (py3.12, pymongo 4.18.1, mockupdb):

  • All 4 new tests fail on master (BytesWarning raised as error / b'...' in description) and pass with the fix.
  • Full directory: pytest tests/integrations/pymongo/55 passed (51 existing + 4 new), also under python -b with 0 BytesWarning lines in output.
  • ruff format / ruff check clean.

Per the discussion in the issue (decode vs. repr): this goes with decoding, since the b'...' form was clearly not intended for span data.

Fixes #4782

…rning

Under `python -b`, stringify BSON bytes values (the `lsid` session id,
a BSON `Binary`/`bytes` subclass, and bytes values inside commands
serialized via `json.dumps(..., default=str)`) emits
`BytesWarning: str() on a bytes instance` and produces useless
`b'...'` strings.

Route these conversions through a small `_bytes_safe_str()` helper that
decodes UTF-8 with a replacement fallback for undecodable bytes, and
adds regression tests that turn BytesWarning into an error.

Fixes getsentry#4782
@DawnofGenX
DawnofGenX requested a review from a team as a code owner September 20, 2026 19:07

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e9b99e0. Configure here.

Comment thread sentry_sdk/integrations/pymongo.py Outdated
…g it

The logical session id is a BSON Binary UUID (random bytes), not text.
UTF-8-decoding it with errors='replace' is lossy and lets distinct ids
collide, defeating its purpose as an identifier. Render it as hex
instead, which is stable and lossless while still avoiding BytesWarning
from str() (getsentry#4782, per Bugbot review).

Co-Authored-By: Claude <noreply@anthropic.com>
@DawnofGenX

Copy link
Copy Markdown
Author

Good catch — fixed in 3ef7ab5. The lsid is now rendered as a lossless hex string via a dedicated _bytes_to_hex() helper (Binary`` bytes → .hex()) instead of UTF-8-decoding random bytes, so distinct session ids stay distinct and no BytesWarning is emitted. The UTF-8 decode remains only for human-readable BSON values like collection names (the json.dumps(default=...) site), where decoding is the right call. The regression test now uses a real 16-byte Binary UUID and asserts the span's operation_ids.session equals the exact hex of the id.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sentry_sdk/integrations/pymongo.py:151: BytesWarning: str() on a bytes instance

1 participant