Skip to content

feat(flutter): Unsampled errors affect release health - #4008

Merged
buenaflor merged 3 commits into
feat/3300-unhandled-session-statusfrom
fix/3786-sampled-unhandled-session
Sep 7, 2026
Merged

buenaflor merged 3 commits into
feat/3300-unhandled-session-statusfrom
fix/3786-sampled-unhandled-session

Conversation

@buenaflor

Copy link
Copy Markdown
Contributor

📜 Description

Add an internal sampled-out event lifecycle hook and use it to keep native session state accurate when an unhandled Dart or Flutter event is dropped by sampling.

The native session integration:

  • receives only final events accepted by processors and beforeSend
  • updates Android or Cocoa with unhandled: true when mechanism.handled == false
  • awaits Android worker persistence before capture returns
  • unregisters on close and contains native failures
  • remains disabled when automatic session tracking is disabled

Stacked on #4007, which adopts the non-terminating envelope APIs. That PR is itself stacked on #4006.

Fixes #3786

💡 Motivation and Context

A sampled-out unhandled error has no envelope, so the native SDK cannot infer its session side effects from capture. Without a separate update, a gracefully ending session is incorrectly reported as exited instead of unhandled.

💚 How did you test it?

  • Core SentryClient sampling suite: 10 tests passed
  • Native session integration, channel, and Android worker suite: 104 tests passed
  • Platform registration suite: 22 tests passed
  • Android release APK build passed
  • Dart and Flutter analysis passed with fatal warnings
  • Dart 3.13 formatting verified
  • Confirmed the Cocoa 9.27.0 private API signatures against the tagged source

The local macOS example build was blocked before compilation by Flutter's experimental Swift Package Manager override identity mismatch (flutter vs sentry_flutter); CI provides the platform build lane.

📝 Checklist

  • I reviewed submitted code
  • I added tests to verify changes
  • No new PII added or SDK only sends newly added PII if sendDefaultPii is enabled
  • I updated the docs if needed
  • All focused tests passing
  • Public API changes reviewed by another Mobile SDK team member or implemented according to the develop docs spec
  • No breaking changes

Made with Cursor

@github-actions

github-actions Bot commented Sep 7, 2026 •

Copy link
Copy Markdown
Contributor

Semver Impact of This PR

⚪ None (no version bump detected)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


No changelog entries will be generated from this PR.


🤖 This preview updates automatically when you update the PR.

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code has higher potential to break the SDK and may be hard to test. To prevent severe bugs, apply the rollout process for releasing such changes and be extra careful when changing and reviewing these files:

  • packages/flutter/darwin/sentry_flutter/Sources/sentry_flutter/SentryFlutterPlugin.swift

@codecov

codecov Bot commented Sep 7, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.58%. Comparing base (f5c4787) to head (ab35c53).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@                          Coverage Diff                           @@
##           feat/3300-unhandled-session-status    #4008      +/-   ##
======================================================================
- Coverage                               93.00%   88.58%   -4.43%     
======================================================================
  Files                                     111      344     +233     
  Lines                                    4346    12295    +7949     
======================================================================
+ Hits                                     4042    10891    +6849     
- Misses                                    304     1404    +1100     
Flag Coverage Δ
sentry 88.40% <100.00%> (?)
sentry_dio 97.95% <ø> (?)
sentry_drift 93.63% <ø> (?)
sentry_file 64.41% <ø> (?)
sentry_firebase_remote_config 100.00% <ø> (ø)
sentry_flutter 92.74% <100.00%> (+0.03%) ⬆️
sentry_grpc 99.11% <ø> (?)
sentry_hive 76.37% <ø> (?)
sentry_isar 73.88% <ø> (?)
sentry_link 22.04% <ø> (?)
sentry_logging 97.01% <ø> (?)
sentry_sqflite 88.88% <ø> (?)
sentry_supabase 97.48% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@buenaflor
buenaflor marked this pull request as ready for review September 7, 2026 11:23
Copilot AI lite review requested due to automatic review settings September 7, 2026 11:23
@buenaflor
buenaflor requested a review from denrase as a code owner September 7, 2026 11:23

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.

🔵 Needs a closer look

It changes the SDK event pipeline and introduces new native interop behavior (Android worker + Cocoa private API) where subtle platform/runtime differences warrant final human validation before approval.

Pull request overview

This PR adds an internal lifecycle hook for events dropped by event sampling and uses it in the Flutter SDK to notify native session tracking when an unhandled Dart/Flutter error is sampled out, keeping native session state accurate even when no envelope is forwarded.

Changes:

  • Dispatch a new internal OnEventSampledOut lifecycle event from SentryClient when sampling drops an event (after processors and beforeSend).
  • Add a Flutter NativeSessionIntegration that listens for sampled-out unhandled errors and triggers a native session update via a new SentryNativeBinding method.
  • Implement the native binding plumbing across method channels (Darwin), Android worker/JNI path, and add targeted regression tests.
File summaries
File Description
packages/dart/lib/src/sentry_client.dart Dispatches OnEventSampledOut when an event is dropped by sampling.
packages/dart/lib/src/sdk_lifecycle_hooks.dart Adds internal lifecycle event OnEventSampledOut.
packages/dart/test/sentry_client_test.dart Adds coverage for sampled-out lifecycle dispatch semantics.
packages/flutter/lib/src/sentry_flutter.dart Registers the new native session integration on Android/iOS/macOS when native is enabled.
packages/flutter/lib/src/integrations/native_session_integration.dart New integration that updates native sessions for sampled-out unhandled events.
packages/flutter/lib/src/native/sentry_native_binding.dart Extends the binding contract with updateSessionForDroppedEventNonTerminating.
packages/flutter/lib/src/native/sentry_native_channel.dart Implements the new binding method via method channels (non-Android).
packages/flutter/lib/src/native/java/sentry_native_java.dart Implements the new binding method via the Android core worker.
packages/flutter/lib/src/native/java/android_core_worker.dart Adds worker request + native call to update session for dropped non-terminating events.
packages/flutter/lib/src/native/c/sentry_native.dart Adds unsupported stub for the new method on the C/FFI binding.
packages/flutter/lib/src/web/sentry_web.dart Adds a “not supported” stub for web.
packages/flutter/darwin/sentry_flutter/Sources/sentry_flutter/SentryFlutterPlugin.swift Adds method-channel handler calling Cocoa internal session update API.
packages/flutter/test/integrations/native_session_integration_test.dart New unit tests for the integration behavior and lifecycle unregistration/error swallowing.
packages/flutter/test/sentry_flutter_test.dart Updates platform integration expectations to include NativeSessionIntegration.
packages/flutter/test/sentry_native_channel_test.dart Adds method-channel coverage for the new native binding call.
packages/flutter/test/native/android_core_worker_test_real.dart Adds coverage ensuring the Android worker path awaits the session update request.
packages/flutter/test/native/sentry_native_java_test_real.dart Updates fake worker to satisfy the new interface surface.
packages/flutter/test/sentry_native/sentry_native_test_ffi.dart Adds unsupported-path test coverage for FFI binding.
packages/flutter/test/mocks.mocks.dart Regenerates mocks to include the new binding method.
Review details
  • Files reviewed: 19/19 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@denrase denrase left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We should check if we need to do this if we drop for ANY reason, not just sampling.

Comment thread packages/dart/test/sentry_client_test.dart
Comment thread packages/dart/test/sentry_client_test.dart
Comment thread packages/dart/test/sentry_client_test.dart
@buenaflor

Copy link
Copy Markdown
Contributor Author

We should check if we need to do this if we drop for ANY reason, not just sampling.

We only wanna do this for sampling.

if an event is dropped due to ignoreErrors, eventProcessor or beforeSend, it's filtered on purpose. however when events are not filtered and reach the sampling stage it means this is an error that we consider as "useful" and want to still reflect in the session even though it might be sampled out.

For details: https://develop.sentry.dev/sdk/foundations/client/#event-pipeline

buenaflor and others added 3 commits September 7, 2026 16:25
Dispatch sampled-out events after processing and update native session state for unhandled errors that do not produce an envelope.

Fixes #3786

Co-Authored-By: Cursor <cursor@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Wrap the non-terminating session update handler signature to comply with the repository SwiftLint limit.

Co-Authored-By: Cursor <cursor@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Clear the retained options reference after unregistering the sampled-out event callback during integration shutdown.

Co-Authored-By: Cursor <cursor@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@buenaflor
buenaflor force-pushed the fix/3786-sampled-unhandled-session branch from f29ab52 to ab35c53 Compare September 7, 2026 14:25
@buenaflor
buenaflor merged commit 7f3c7dc into v10-branch Sep 7, 2026
137 of 269 checks passed
@buenaflor
buenaflor deleted the fix/3786-sampled-unhandled-session branch September 7, 2026 14:26
@buenaflor buenaflor changed the title fix(flutter): Track sampled unhandled errors feat(flutter): Unsampled errors affect release health Sep 8, 2026
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.

3 participants