From 26b17b42b337d37587982b92ea36a568c33efc4c Mon Sep 17 00:00:00 2001 From: Antonis Lilis Date: Fri, 17 Apr 2026 11:26:58 +0200 Subject: [PATCH] fix(ios): honor _experiments.enableUnhandledCPPExceptionsV2 on v8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same dead-code issue as the profiling fix — `SentrySDKWrapper` parses `_experiments.enableUnhandledCPPExceptionsV2`, but `RNSentryStart` (the live init path since v8.0.0) does not. Port the handling into the `_experiments` block just introduced for `profilingOptions`, and add enabled/disabled/default XCTest coverage on `RNSentryStart`. Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 1 + .../RNSentryCocoaTesterTests/RNSentryTests.m | 54 +++++++++++++++++++ packages/core/ios/RNSentryStart.m | 8 ++- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b777b1552..62d7b072ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ ### Fixes - Fix iOS UI profiling options being silently ignored since v8.0.0 ([#6012](https://github.com/getsentry/sentry-react-native/pull/6012)) +- Fix `_experiments.enableUnhandledCPPExceptionsV2` being silently ignored on iOS since v8.0.0 ## 8.8.0 diff --git a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryTests.m b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryTests.m index b09a2073d0..8720db3b93 100644 --- a/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryTests.m +++ b/packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryTests.m @@ -1470,6 +1470,60 @@ - (void)testStartCreateOptionsWithDictionaryEmptyExperimentsDoesNotInstallConfig } #endif +- (void)testStartCreateOptionsWithDictionaryEnableUnhandledCPPExceptionsV2Enabled +{ + NSError *error = nil; + + NSDictionary *_Nonnull mockedReactNativeDictionary = @{ + @"dsn" : @"https://abcd@efgh.ingest.sentry.io/123456", + @"_experiments" : @ { + @"enableUnhandledCPPExceptionsV2" : @YES, + }, + }; + SentryOptions *actualOptions = + [RNSentryStart createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; + + XCTAssertNotNil(actualOptions, @"Did not create sentry options"); + XCTAssertNil(error, @"Should not pass no error"); + XCTAssertTrue(actualOptions.experimental.enableUnhandledCPPExceptionsV2, + @"enableUnhandledCPPExceptionsV2 should be enabled"); +} + +- (void)testStartCreateOptionsWithDictionaryEnableUnhandledCPPExceptionsV2Disabled +{ + NSError *error = nil; + + NSDictionary *_Nonnull mockedReactNativeDictionary = @{ + @"dsn" : @"https://abcd@efgh.ingest.sentry.io/123456", + @"_experiments" : @ { + @"enableUnhandledCPPExceptionsV2" : @NO, + }, + }; + SentryOptions *actualOptions = + [RNSentryStart createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; + + XCTAssertNotNil(actualOptions, @"Did not create sentry options"); + XCTAssertNil(error, @"Should not pass no error"); + XCTAssertFalse(actualOptions.experimental.enableUnhandledCPPExceptionsV2, + @"enableUnhandledCPPExceptionsV2 should be disabled"); +} + +- (void)testStartCreateOptionsWithDictionaryEnableUnhandledCPPExceptionsV2Default +{ + NSError *error = nil; + + NSDictionary *_Nonnull mockedReactNativeDictionary = @{ + @"dsn" : @"https://abcd@efgh.ingest.sentry.io/123456", + }; + SentryOptions *actualOptions = + [RNSentryStart createOptionsWithDictionary:mockedReactNativeDictionary error:&error]; + + XCTAssertNotNil(actualOptions, @"Did not create sentry options"); + XCTAssertNil(error, @"Should not pass no error"); + XCTAssertFalse(actualOptions.experimental.enableUnhandledCPPExceptionsV2, + @"enableUnhandledCPPExceptionsV2 should default to disabled"); +} + - (void)testStartEventFromSentryCocoaReactNativeHasOriginAndEnvironmentTags { SentryEvent *testEvent = [[SentryEvent alloc] init]; diff --git a/packages/core/ios/RNSentryStart.m b/packages/core/ios/RNSentryStart.m index c7faf91dae..75cd626515 100644 --- a/packages/core/ios/RNSentryStart.m +++ b/packages/core/ios/RNSentryStart.m @@ -100,9 +100,15 @@ + (SentryOptions *_Nullable)createOptionsWithDictionary:(NSDictionary *_Nonnull) } } - // Configure iOS UI Profiling from _experiments.profilingOptions + // Configure experimental options from _experiments NSDictionary *experiments = mutableOptions[@"_experiments"]; if (experiments != nil && [experiments isKindOfClass:[NSDictionary class]]) { + BOOL enableUnhandledCPPExceptions = + [experiments[@"enableUnhandledCPPExceptionsV2"] boolValue]; + [RNSentryExperimentalOptions setEnableUnhandledCPPExceptionsV2:enableUnhandledCPPExceptions + sentryOptions:sentryOptions]; + + // Configure iOS UI Profiling NSDictionary *profilingOptions = experiments[@"profilingOptions"]; if (profilingOptions != nil && [profilingOptions isKindOfClass:[NSDictionary class]]) { [RNSentryExperimentalOptions configureProfilingWithOptions:profilingOptions