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

address bot comment

8c711b3
Select commit
Loading
Failed to load commit list.
@sentry/warden / warden: find-bugs completed Jul 3, 2026 in 0s

6 issues

find-bugs: Found 6 issues (6 low)

Low

`DataCollectionUserOptions` fields do not allow `None` but runtime accepts it - `sentry_sdk/_types.py:191-201`

Fields like cookies, http_headers, query_params, graphql, gen_ai, and database are typed as non-optional TypedDict values, but _resolve_explicit in data_collection.py explicitly handles None for each via the or {} pattern, and the test none_values_fall_back_to_spec_defaults validates this behaviour. Type checkers will flag data_collection={"cookies": None} as an error even though it's valid and documented SDK input; fields should be typed as Optional[KeyValueCollectionBehaviour] etc.

`DeprecationWarning` for `send_default_pii` uses `stacklevel=2` and points to SDK internals instead of user code - `sentry_sdk/_types.py:191`

In sentry_sdk/data_collection.py, resolve_data_collection emits warnings.warn(..., stacklevel=2) when both data_collection and send_default_pii are set. When reached via sentry_sdk.init(), the call chain is resolve_data_collection_get_options_Client.__init___init → user code, so stacklevel=2 resolves to the resolve_data_collection(rv) call inside _get_options (client.py:353) rather than the user's sentry_sdk.init() call site. The warning therefore points at SDK internals, making it harder for users to locate the deprecated usage. Increase stacklevel to account for the full call chain.

Also found at:

  • sentry_sdk/consts.py:1282
  • sentry_sdk/data_collection.py:256
`BaseClient.data_collection` returns a shared mutable global dict - `sentry_sdk/client.py:441-443`

BaseClient.data_collection (inherited by NonRecordingClient) returns the module-level _DISABLED_DATA_COLLECTION_CONFIG dict directly, with no copy. This dict has nested mutable sub-dicts and a single terms list aliased across cookies, http_headers.request, http_headers.response, and query_params. Any caller that mutates the returned config (e.g. client.data_collection["cookies"]["mode"] = "off") would permanently corrupt the shared global for all subsequent callers. No consumer mutates it today (the PR does not yet wire data_collection to any behavior), so this is a latent correctness/code-quality issue rather than an active bug.

`_resolve_explicit` raises `AttributeError` on truthy non-dict sub-field values - `sentry_sdk/consts.py:1282`

In data_collection.py, _resolve_explicit uses d.get("cookies") or {} (and the same for query_params, graphql, gen_ai, database) which only replaces None/falsy values with {}; a truthy but non-dict value such as the string "off" passes through unchanged and is handed to the _*_from_value() helpers, which immediately call .get() on it, raising an obscure AttributeError: 'str' object has no attribute 'get' instead of a clear validation error. Notably, http_headers accepts a shorthand "off" string (see test at line 31), so a user could reasonably expect cookies: "off" to work too, but it crashes with an unhelpful error.

Also found at:

  • tests/test_data_collection.py:32-38
`http_bodies` set to a non-iterable (e.g. `False`) raises an unhelpful TypeError during config resolution - `sentry_sdk/data_collection.py:145-147`

In _resolve_explicit, http_bodies is normalized via list(http_bodies) if http_bodies is not None else list(ALL_HTTP_BODY_TYPES). The only guard is is not None, so any non-iterable, non-None value (e.g. a user passing http_bodies=False to opt out, by analogy with the boolean shorthand documented for frame_context_lines) reaches list(False) and raises TypeError: 'bool' object is not iterable. This crashes client initialization with a confusing error instead of either honoring the intent or raising a clear validation message. Note the documented opt-out for http_bodies is [] (and the type is List[str]), so False is a type violation rather than a supported shorthand — but the resulting failure mode is a low-level TypeError rather than a helpful error, unlike the explicit isinstance(..., bool) handling given to frame_context_lines.

Deprecation warning for `send_default_pii` points to SDK internals, not user code

In sentry_sdk/data_collection.py, warnings.warn is called with stacklevel=2, which makes the warning appear to originate from _get_options in client.py rather than from the user's sentry_sdk.init() call. Users who set both send_default_pii and data_collection will see a warning pointing at an internal SDK file, making it hard to trace back to their own code.


⏱ 17m 37s · 6.9M in / 200.6k out · $7.56