Skip to content

fix: loosen StatsigEventSerializer validation and downgrade DetectorGroup.DoesNotExist noise#119482

Closed
billyvg wants to merge 1 commit into
masterfrom
claude/serene-cannon-x38v7j
Closed

fix: loosen StatsigEventSerializer validation and downgrade DetectorGroup.DoesNotExist noise#119482
billyvg wants to merge 1 commit into
masterfrom
claude/serene-cannon-x38v7j

Conversation

@billyvg

@billyvg billyvg commented Jul 13, 2026

Copy link
Copy Markdown
Member

Summary

Fixes two production Sentry alerts surfaced by automated monitoring.


Fix 1 — SENTRY-5J6Z: Statsig webhook DeserializationError (medium severity, ~17k events/day, 4826 users impacted)

Root cause: StatsigEventSerializer.user was declared as DictField(child=CharField()), which requires every value in the dict to be a plain string. Statsig server-SDK payloads (e.g. statsig-server-core-node) send nested objects for user.customIDs, user.custom, and user.statsigEnvironment. This caused every such webhook to fail with a DeserializationError before flag audit logs could be written.

Two additional fields also caused spurious failures:

  • value — Statsig sends an empty string for exposure events; CharField without allow_blank=True rejects it.
  • timeUUID — Sent in formats that don't satisfy DRF's UUIDField; changed to CharField since this field is unused by the handler.

Fix: Remove the child=CharField() constraint from user, add allow_blank=True to value, and relax timeUUID to CharField. None of these fields are used downstream in the audit-log construction path.

Files changed:

  • src/sentry/flags/providers.py — relax StatsigEventSerializer field constraints
  • tests/sentry/flags/providers/test_statsig.py — add regression test with nested user fields

Fix 2 — SENTRY-5R4N: DetectorGroup.DoesNotExist logged as exception (medium severity, ~27k events, 4800 users triggering noisy errors)

Root cause: _get_detector_for_group in sentry/workflow_engine/processors/detector.py used logger.exception() inside the DetectorGroup.DoesNotExist handler. logger.exception() attaches the exception traceback and triggers a Sentry capture, but this DoesNotExist is an expected condition for legacy groups that were created before the workflow engine's DetectorGroup table existed. The function already falls through correctly to two further lookup strategies; the exception capture was pure instrumentation noise.

Fix: Downgrade logger.exception()logger.warning() so the condition is noted in logs without generating a Sentry event.

Files changed:

  • src/sentry/workflow_engine/processors/detector.py — downgrade log level

Evidence / Reasoning

Legal Boilerplate

Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms.


Generated by Claude Code

…roup.DoesNotExist log level

Two Sentry alert fixes:

1. SENTRY-5J6Z: StatsigEventSerializer rejects Statsig server-SDK payloads where
   user.customIDs, user.custom, and user.statsigEnvironment are nested objects
   rather than flat strings. Remove child=CharField() constraint on the user
   DictField and allow blank values on value/timeUUID fields that are not used
   by the handler logic anyway.

2. SENTRY-5R4N: _get_detector_for_group uses logger.exception() for a
   DetectorGroup.DoesNotExist that is an expected condition for legacy groups
   that predate the workflow engine. This generates ~27k noisy Sentry events
   affecting ~4800 users. Downgrade to logger.warning() since the fallback
   lookup path already handles this case correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0152iRwgLj2pwmC8VKUsxoKL
@github-actions github-actions Bot added Scope: Backend Automatically applied to PRs that change backend components Scope: Frontend Automatically applied to PRs that change frontend components labels Jul 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🚨 Warning: This pull request contains Frontend and Backend changes!

It's discouraged to make changes to Sentry's Frontend and Backend in a single pull request. The Frontend and Backend are not atomically deployed. If the changes are interdependent of each other, they must be separated into two pull requests and be made forward or backwards compatible, such that the Backend or Frontend can be safely deployed independently.

Have questions? Please ask in the #discuss-dev-infra channel.

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

Labels

Scope: Backend Automatically applied to PRs that change backend components Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants