Skip to content

Commit 1502cde

Browse files
antonisclaude
andauthored
fix(ios): Don't crash on a null DSN in sentry.options.json (#6958)
* fix(ios): Don't crash on a null DSN in sentry.options.json An options file with `"dsn": null` passed NSNull into getURLFromDSN:, which threw an NSInvalidArgumentException at launch. Android already guards this case. Also adds tests for the RNSentrySDK start paths: null DSN in the options file, an invalid DSN set in configureOptions, and starting from JS after a skipped native start. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: Add changelog entry for #6958 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(ios): Keep getURLFromDSN signature unchanged Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 60b990d commit 1502cde

3 files changed

Lines changed: 46 additions & 0 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- Support Expo Router 58 in `expoRouterIntegration`. Metro no longer warns about the removed `expo-router/build/global-state/router-store` module, and the integration creates navigation spans again ([#6923](https://github.com/getsentry/sentry-react-native/pull/6923))
1717
- Start the native iOS SDK from `RNSentrySDK` when `sentry.options.json` is missing or can't be parsed and the DSN is set in `configureOptions` ([#6956](https://github.com/getsentry/sentry-react-native/pull/6956))
1818
- The fallback options always failed to parse, so `configureOptions` never ran. Before 8.30.0 the app crashed at launch; since then the native SDK silently never started.
19+
- Don't crash the iOS app at launch when `sentry.options.json` contains `"dsn": null` ([#6958](https://github.com/getsentry/sentry-react-native/pull/6958))
1920

2021
### Internal
2122

‎packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryStartFromFileTests.swift‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,47 @@ final class RNSentryStartFromFileTests: XCTestCase {
9898
XCTAssertEqual(actualOptions.environment, "new-environment")
9999
}
100100

101+
func testDoesNotStartWithNullDsnInOptionsFile() throws {
102+
let path = try writeTemporaryOptionsFile("{ \"dsn\": null, \"environment\": \"environment-from-null-dsn-file\" }")
103+
defer { try? FileManager.default.removeItem(atPath: path) }
104+
105+
var wasConfigurationCalled = false
106+
RNSentrySDK.start(path, configureOptions: { options in
107+
wasConfigurationCalled = true
108+
XCTAssertEqual(options.environment, "environment-from-null-dsn-file")
109+
})
110+
111+
XCTAssertTrue(wasConfigurationCalled)
112+
XCTAssertFalse(SentrySDK.isEnabled)
113+
}
114+
115+
func testDoesNotStartWhenConfigureOptionsSetsInvalidDsn() {
116+
RNSentrySDK.start(getValidOptionsPath(), configureOptions: { options in
117+
options.dsn = "invalid-dsn"
118+
})
119+
120+
XCTAssertFalse(SentrySDK.isEnabled)
121+
}
122+
123+
func testStartsFromJsAfterSkippedNativeStart() throws {
124+
RNSentrySDK.start(getNonExistingOptionsPath(), configureOptions: nil)
125+
XCTAssertFalse(SentrySDK.isEnabled)
126+
127+
var error: NSError?
128+
RNSentryStart.start(options: ["dsn": "https://abcd@efgh.ingest.sentry.io/123456"], error: &error)
129+
130+
XCTAssertNil(error)
131+
XCTAssertTrue(SentrySDK.isEnabled)
132+
XCTAssertEqual(SentrySDK.internal.options.dsn, "https://abcd@efgh.ingest.sentry.io/123456")
133+
}
134+
135+
func writeTemporaryOptionsFile(_ content: String) throws -> String {
136+
let url = FileManager.default.temporaryDirectory
137+
.appendingPathComponent("\(UUID().uuidString).options.json")
138+
try content.write(to: url, atomically: true, encoding: .utf8)
139+
return url.path
140+
}
141+
101142
func getNonExistingOptionsPath() -> String {
102143
return "/non-existing.options.json"
103144
}

‎packages/core/ios/RNSentryStart.m‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@ + (void)setEventEnvironmentTag:(SentryEvent *)event
303303

304304
+ (NSString *_Nullable)getURLFromDSN:(NSString *)dsn
305305
{
306+
// The options file may contain `"dsn": null`, which arrives here as NSNull.
307+
if (![dsn isKindOfClass:[NSString class]]) {
308+
return nil;
309+
}
306310
NSURL *url = [NSURL URLWithString:dsn];
307311
if (!url) {
308312
return nil;

0 commit comments

Comments
 (0)