Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Conversation

bitsandfoxes
Copy link
Contributor

@bitsandfoxes bitsandfoxes commented Oct 14, 2025

Problem

The SDK should use the new SessionEndStatus.Unhandled when capturing an unhandled exception that does not cause the application to crash.

Unhandled exceptions typically lead to a terminal state of the application. The only exception (hehe) to this was the UnobservedTaskExceptionIntegration. Another instance where this is highly relevant is Unity: Unhandled exceptions get "swallowed" by the engine and the game just continues.

Context

Within the Sentry SDK for .NET the only non-terminal unhandled exception comes from the UnobservedTaskExceptionIntegration that also gets special cased in SentryEvent.HasTerminalException() where we compare against the mechanism key

if (Exception?.Data[Mechanism.HandledKey] is false)
{
return Exception.Data[Mechanism.MechanismKey] as string != UnobservedTaskExceptionIntegration.MechanismKey;
}

This is limiting as it does not allow for other integrations i.e. coming from the Unity SDK to add to this check.

Proposal

Option 1: Add list of NonTerminalMechanismKey on the options

One straight forward solution to this would be to have an internal List<string>? NonTerminalMechanismKeys; on
the options and have integrations add to the list during their registration. We'd need to pass the options into the HasTerminalException check but they are available everywhere we'd need them.

There are a couple of downsides to this:

  1. Should the list be internal or public. If we keep it internal the Unity SDK can add to it but no user written integration can.
  2. We're polluting the options with one more list of things.
  3. It's just a bunch of string comparisons that make this work

Option 2: Rework the Mechanism bool? Handled to an explicit enum ExceptionHandledState

The Terminal state is only ever relevant in case of an Unhandled Exception. This makes the additional property somewhat redundant. An alternative solution would be to replace the bool? Handled with an explicit ExceptionHandledState. This would be quite the breaking change and we'd need to take special care during serialization.

public enum ExceptionHandledState
{
    /// <summary>Exception was never thrown (constructed and captured)</summary>
    NotThrown,

    /// <summary>Exception was caught by user code</summary>
    Handled,

    /// <summary>Unhandled exception that causes application termination</summary>
    UnhandledTerminal,

    /// <summary>Unhandled exception that doesn't cause termination (e.g., UnobservedTask, Unity)</summary>
    UnhandledNonTerminal
}

public ExceptionHandledState? HandledState { get; set; }

Option 3: Extend Mechanism to have a bool? Terminal property

The mechanism on the exception already has things like Handled and Synthetic. We could extend this by adding bool? Terminal. Integrations that capture unhandled non-terminal exceptions can set the Terminal state to false and we can check for this on the SentryEvent.

This sounds to me the most pragmatic and minimal invasive change. The only downside I can see right now is that the property is only ever going to be useful when Handled is false. But we can keep it nullable.

@bitsandfoxes bitsandfoxes changed the base branch from main to version6 October 14, 2025 16:04
Copy link
Contributor

github-actions bot commented Oct 14, 2025

Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against d657e0b

Copy link

codecov bot commented Oct 15, 2025

Codecov Report

❌ Patch coverage is 89.65517% with 3 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (version6@90a3823). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/Sentry/Protocol/Mechanism.cs 66.66% 2 Missing ⚠️
src/Sentry/SentryEvent.cs 87.50% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             version6    #4633   +/-   ##
===========================================
  Coverage            ?   73.21%           
===========================================
  Files               ?      480           
  Lines               ?    17417           
  Branches            ?     3437           
===========================================
  Hits                ?    12751           
  Misses              ?     3812           
  Partials            ?      854           

☔ View full report in Codecov by Sentry.
📢 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.

@bitsandfoxes bitsandfoxes marked this pull request as ready for review October 15, 2025 14:37
@bitsandfoxes
Copy link
Contributor Author

This is really annoying.. running ./build.sh on a beefed up m3

Build failed with 13 error(s) and 4 warning(s) in 1444.0s

because

Could not find android.jar for API level 36. This means the Android SDK platform for API level 36 is not installed; 
it was expected to be in `/Users/bitfox/Library/Android/sdk/platforms/android-36/android.jar`.

and all I want to do is to please Verify...

cursor[bot]

This comment was marked as outdated.

Copy link
Member

@bruno-garcia bruno-garcia left a comment

Choose a reason for hiding this comment

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

while talking through this a bigger problem has been uncovered, with restarting sessions on unhandled

if (exception.Data[Mechanism.TerminalKey] is bool terminal)
{
mechanism.Terminal = terminal;
exception.Data.Remove(Mechanism.TerminalKey);
Copy link
Member

Choose a reason for hiding this comment

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

do we need to remove? curious why

var source = json.GetPropertyOrNull("source")?.GetString();
var helpLink = json.GetPropertyOrNull("help_link")?.GetString();
var handled = json.GetPropertyOrNull("handled")?.GetBoolean();
var terminal = json.GetPropertyOrNull("terminal")?.GetBoolean();
Copy link
Member

Choose a reason for hiding this comment

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

looks like wer'e changing the wire protocol here. Do we need this? afaik the Exception interface has some Data bag we could use instead.

In any case we need to check this is even accepted by Relay

Copy link
Member

Choose a reason for hiding this comment

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

I only spotted the changes to the SessionUpdate protocol:

Are there also changes to the Mechanism protocol?

Copy link
Member

Choose a reason for hiding this comment

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

All server changes so far are about sessions. Nothing related to events

var source = json.GetPropertyOrNull("source")?.GetString();
var helpLink = json.GetPropertyOrNull("help_link")?.GetString();
var handled = json.GetPropertyOrNull("handled")?.GetBoolean();
var terminal = json.GetPropertyOrNull("terminal")?.GetBoolean();
Copy link
Member

Choose a reason for hiding this comment

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

I only spotted the changes to the SessionUpdate protocol:

Are there also changes to the Mechanism protocol?

return SentryExceptions?.Any(e => e.Mechanism is { Handled: false }) ?? false;
}

internal bool HasUnhandledNonTerminalException()
Copy link
Member

Choose a reason for hiding this comment

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

question: order

Do I get that right that, for correct consumption, we need to call these methods in this order

  1. HasUnhandledNonTerminalException
  2. HasUnhandledException
  3. HasException

Then there is also HasTerminalException.

It's a bit confusing to me ... I wonder if this could be designed a bit more clearly.
On the other hand ... this may just be me ... and the methods are all internal.

/// <summary>
/// Session ended with an unhandled exception.
/// </summary>
Unhandled,
Copy link
Member

Choose a reason for hiding this comment

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

question: breaking change

We ship this in a major release, so this may be a non-concern.

But inserting an enum member is a breaking change for users that have code like:

_ = (SessionEndStatus)1;

Well ... I guess it's unlikely that a considerable amount of user code does this ... I just wanted to hear your thoughts.

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.

4 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.