Skip to content

feat(data-collection): create DataCollection option in client#6702

Draft
ericapisani wants to merge 20 commits into
masterfrom
ep/db-spec-experiement-foundation-dict
Draft

feat(data-collection): create DataCollection option in client#6702
ericapisani wants to merge 20 commits into
masterfrom
ep/db-spec-experiement-foundation-dict

fix: import Literal for mypy type comment

726edeb
Select commit
Loading
Failed to load commit list.
@sentry/warden / warden: code-review completed Jul 2, 2026 in 0s

5 issues

code-review: Found 5 issues (1 medium, 4 low)

Medium

`_kvcb_from_value` raises `AttributeError` instead of a descriptive error for non-dict inputs - `sentry_sdk/data_collection.py:168-169`

If a user passes a non-dict value for cookies or query_params (e.g. data_collection={"cookies": "off"}), val.get("mode", "deny_list") raises AttributeError: 'str' object has no attribute 'get' with no guidance on what went wrong. Consider adding an isinstance(val, dict) guard with a clear TypeError or ValueError.

Also found at:

  • sentry_sdk/consts.py:1282
  • sentry_sdk/consts.py:1451-1454
  • sentry_sdk/data_collection.py:254

Low

`graphql.document` docstring contradicts implementation in `_map_from_send_default_pii` - `sentry_sdk/client.py:27`

The docstring for _map_from_send_default_pii states that graphql.document "stays True" regardless of send_default_pii, while only graphql.variables and database.query_params follow it. The implementation instead sets graphql.document to send_default_pii, so it becomes False when PII is disabled. This is either a documentation error or a behavioral bug: if the spec intends the GraphQL query structure (document, not the PII-bearing variables) to always be collected, then gating it on send_default_pii is wrong. At minimum the contradiction will mislead maintainers about intended PII behavior. Worth confirming against the data-collection spec whether graphql.document should be gated on PII.

DeprecationWarning for `send_default_pii` points to internal SDK code instead of user callsite - `sentry_sdk/consts.py:1282`

The stacklevel=2 in resolve_data_collection (data_collection.py:253) points the warning to _get_options in client.py rather than the user's sentry_sdk.init() call. The actual call depth is: user → _initClient.__init___get_optionsresolve_data_collectionwarnings.warn, so a larger stacklevel is needed to surface the correct file/line in user code.

Also found at:

  • sentry_sdk/consts.py:1438-1440
  • sentry_sdk/data_collection.py:252
`_http_headers_from_value` uses substring `in` on str values, masking malformed input and risking AttributeError - `sentry_sdk/data_collection.py:186-196`

_http_headers_from_value is typed to receive a dict but is fed d.get("http_headers", {}) with no type check. It uses "request" in val / "response" in val, which for a string performs a substring search rather than a key lookup. The test at test_http_headers_collection_defaults documents passing the str "off" as an invalid option and relies on this accident (neither "request" nor "response" is a substring of "off", so both fields silently fall back to deny_list). If a user instead passes a string that contains "request" or "response" (e.g. "incoming request"), the condition becomes True and val["request"] returns a single character, which is passed to _kvcb_from_value(...) and raises an unhelpful AttributeError (str has no .get). Adding an isinstance(val, dict) guard would make malformed input fail cleanly (or fall back to defaults) instead of silently masking it. Impact is limited to unsupported/malformed configuration input.

Also found at:

  • tests/test_data_collection.py:31-36
No test for `TypeError` when `data_collection` receives a non-dict value - `tests/test_data_collection.py:12-13`

The resolve_data_collection function explicitly raises TypeError when data_collection is not a dict, but there is no test exercising this path — unlike test_kvcb_invalid_mode which covers the ValueError for invalid modes.


⏱ 10m 35s · 4.1M in / 135.1k out · $5.30

Annotations

Check warning on line 169 in sentry_sdk/data_collection.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: code-review

`_kvcb_from_value` raises `AttributeError` instead of a descriptive error for non-dict inputs

If a user passes a non-dict value for `cookies` or `query_params` (e.g. `data_collection={"cookies": "off"}`), `val.get("mode", "deny_list")` raises `AttributeError: 'str' object has no attribute 'get'` with no guidance on what went wrong. Consider adding an `isinstance(val, dict)` guard with a clear `TypeError` or `ValueError`.

Check warning on line 1282 in sentry_sdk/consts.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: code-review

[TTU-25E] `_kvcb_from_value` raises `AttributeError` instead of a descriptive error for non-dict inputs (additional location)

If a user passes a non-dict value for `cookies` or `query_params` (e.g. `data_collection={"cookies": "off"}`), `val.get("mode", "deny_list")` raises `AttributeError: 'str' object has no attribute 'get'` with no guidance on what went wrong. Consider adding an `isinstance(val, dict)` guard with a clear `TypeError` or `ValueError`.

Check warning on line 1454 in sentry_sdk/consts.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: code-review

[TTU-25E] `_kvcb_from_value` raises `AttributeError` instead of a descriptive error for non-dict inputs (additional location)

If a user passes a non-dict value for `cookies` or `query_params` (e.g. `data_collection={"cookies": "off"}`), `val.get("mode", "deny_list")` raises `AttributeError: 'str' object has no attribute 'get'` with no guidance on what went wrong. Consider adding an `isinstance(val, dict)` guard with a clear `TypeError` or `ValueError`.

Check warning on line 254 in sentry_sdk/data_collection.py

See this annotation in the file changed.

@sentry-warden sentry-warden / warden: code-review

[TTU-25E] `_kvcb_from_value` raises `AttributeError` instead of a descriptive error for non-dict inputs (additional location)

If a user passes a non-dict value for `cookies` or `query_params` (e.g. `data_collection={"cookies": "off"}`), `val.get("mode", "deny_list")` raises `AttributeError: 'str' object has no attribute 'get'` with no guidance on what went wrong. Consider adding an `isinstance(val, dict)` guard with a clear `TypeError` or `ValueError`.