Skip to content

feat: Add public API for checking unhandled exceptions - #5177

Merged
Flash0ver merged 8 commits into
mainfrom
fix/issue-2877-unhandled-exception-api
Jul 7, 2026
Merged

feat: Add public API for checking unhandled exceptions#5177
Flash0ver merged 8 commits into
mainfrom
fix/issue-2877-unhandled-exception-api

Conversation

@jamescrosswell

@jamescrosswell jamescrosswell commented May 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds two new public extension methods to SentryEvent:

  • IsFromUnhandledException(): Checks if the event is from any unhandled exception
  • IsFromTerminalException(): Checks if the event is from a terminal (crash-causing) exception

Motivation

Fixes #2877

Users need to filter events in callbacks like BeforeSend based on whether exceptions are unhandled/terminal. This is particularly useful in MAUI apps where you might want to filter out common exceptions (like network timeouts) but always capture them if they're terminal.

Implementation

Following @bruno-garcia's feedback, this uses extension methods rather than making internal methods public. The methods check both Exception.Data flags and SentryExceptions mechanism properties.

Key differences:

  • IsFromUnhandledException: Returns true for any unhandled exception (terminal or non-terminal)
  • IsFromTerminalException: Returns true only for unhandled exceptions that are terminal (caused app crash)

Both are well-documented with XML docs and usage examples.

Exception.Data vs SentryException.Mechanism

These representations the same information at different pipeline stages.

  • Exception.Data[Mechanism.HandledKey] is the input form. Unhandled-exception hooks set this in the raw System.Exception's Data dictionary.
  • SentryException.Mechanism is what gets serialized and sent to Sentry.
  • MainExceptionProcessor:171 converts the prior to the later

That's why the API checks both sources - depending on when someone calls it, the truth lives in a different place - and why the tests need to cover both variants.

They will never, in practice, be divergent/inconsistent so that's not a scenario we need to worry about.

🤖 Generated with Claude Code

Changelog Entry

Add public API for checking unhandled exceptions (SentryEventExtensions.IsFromUnhandledException) and terminal exceptions (SentryEventExtensions.IsFromTerminalException)

jamescrosswell and others added 2 commits May 1, 2026 13:12
Adds two new public extension methods to SentryEvent:
- IsFromUnhandledException(): Checks if event is from any unhandled exception
- IsFromTerminalException(): Checks if event is from a terminal (crash-causing) exception

This addresses the need to filter events based on whether they're unhandled/terminal,
particularly useful in MAUI apps where users want to always capture terminal exceptions
even if they match other filters (e.g., network timeouts).

The implementation uses extension methods as suggested by @bruno-garcia, providing a
clean public API without exposing internal methods. Both methods check Exception.Data
and SentryExceptions for the handled/terminal flags.

Fixes #2877

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@codecov

codecov Bot commented May 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 74.17%. Comparing base (1d43862) to head (198a4c6).
⚠️ Report is 82 commits behind head on main.

Files with missing lines Patch % Lines
src/Sentry/SentryEvent.cs 87.50% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5177      +/-   ##
==========================================
+ Coverage   74.08%   74.17%   +0.08%     
==========================================
  Files         506      509       +3     
  Lines       18247    18363     +116     
  Branches     3564     3590      +26     
==========================================
+ Hits        13519    13621     +102     
- Misses       3858     3869      +11     
- Partials      870      873       +3     

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jamescrosswell
jamescrosswell marked this pull request as ready for review May 5, 2026 02:27
@jamescrosswell
jamescrosswell requested a review from Flash0ver as a code owner May 5, 2026 02:27
Comment thread src/Sentry/SentryEventExtensions.cs Outdated
…n methods

HasUnhandledException() and HasUnhandledNonTerminalException() duplicated
the logic in the new public extension methods. Removed the private methods
and updated GetExceptionType() to call IsFromUnhandledException() and
IsFromTerminalException() directly.

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

@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.

Reviewed by Cursor Bugbot for commit 8fc8368. Configure here.

Comment thread src/Sentry/SentryEvent.cs Outdated
IsFromUnhandledException() && !IsFromTerminalException() is not equivalent
to the original per-exception AND check. When SentryExceptions contains a
mix of terminal and non-terminal unhandled exceptions, IsFromTerminalException()
returns true (finding the terminal one), incorrectly suppressing the
UnhandledNonTerminal result.

Restore the private method with its original body. HasUnhandledException()
remains replaced by the public IsFromUnhandledException() extension method,
which is a true semantic equivalent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jamescrosswell
jamescrosswell marked this pull request as draft May 7, 2026 00:37
@jamescrosswell
jamescrosswell marked this pull request as ready for review May 7, 2026 04:52
@jamescrosswell
jamescrosswell marked this pull request as draft May 7, 2026 04:54
@jamescrosswell
jamescrosswell marked this pull request as ready for review May 11, 2026 06:06
Comment thread src/Sentry/SentryEventExtensions.cs Outdated
Comment thread src/Sentry/SentryEventExtensions.cs
Comment thread test/Sentry.Tests/SentryEventExtensionsTests.cs
Comment thread src/Sentry/SentryEventExtensions.cs Outdated
Address review feedback: keep the exception-mechanism inspection logic
alongside the other Has* methods in SentryEvent for cohesion. The public
IsFromUnhandledException/IsFromTerminalException extension methods now
delegate to internal HasUnhandledException/HasUnhandledTerminalException,
and GetExceptionType calls the internal method directly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address review feedback: cover a handled exception supplied via
SentryExceptions/Mechanism (Handled = true), which returns false — the
Mechanism equivalent of IsFromTerminalException_HandledExceptionInExceptionProperty_ReturnsFalse.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jamescrosswell
jamescrosswell requested a review from Flash0ver July 6, 2026 22:39
@Flash0ver Flash0ver changed the title Add public API for checking unhandled exceptions feat: Add public API for checking unhandled exceptions Jul 7, 2026
@Flash0ver
Flash0ver merged commit 29ef560 into main Jul 7, 2026
55 of 56 checks passed
@Flash0ver
Flash0ver deleted the fix/issue-2877-unhandled-exception-api branch July 7, 2026 10:10
jamescrosswell added a commit to getsentry/sentry-docs that referenced this pull request Jul 10, 2026
…18676)

## DESCRIBE YOUR PR

Documents the new `SentryEvent.IsFromUnhandledException()` and
`SentryEvent.IsFromTerminalException()` extension methods (added in
getsentry/sentry-dotnet#5177) so users can find them where they're most
likely to be used — the `before-send` filtering docs.

- Adds a "Filtering by Unhandled or Terminal Exceptions" subsection
under **Using before-send** in the .NET filtering docs
- Explains the difference between unhandled and terminal exceptions
- Provides C# and F# examples for filtering handled exceptions while
always sending unhandled ones

Closes getsentry/sentry-dotnet#5348

## IS YOUR CHANGE URGENT?

Help us prioritize incoming PRs by letting us know when the change needs
to go live.
- [ ] Urgent deadline (GA date, etc.): <!-- ENTER DATE HERE -->
- [x] Other deadline: Release of `sentry-dotnet v6.7.0`
- [ ] None: Not urgent, can wait up to 1 week+

## SLA

- Teamwork makes the dream work, so please add a reviewer to your PRs.
- Please give the docs team up to 1 week to review your PR unless you've
added an urgent due date to it.
Thanks in advance for your help!

## PRE-MERGE CHECKLIST

*Make sure you've checked the following before merging your changes:*

- [x] Checked Vercel preview for correctness, including links
- [x] PR was reviewed and approved by any necessary SMEs (subject matter
experts)
- [ ] PR was reviewed and approved by a member of the [Sentry docs
team](https://github.com/orgs/getsentry/teams/docs)

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: medium PR risk score: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make SentryEvent.HasTerminalException() public

2 participants