Skip to content

fix(replay): Guard against non-dictionary touch breadcrumb path elements#6346

Merged
antonis merged 2 commits into
mainfrom
fix/replay-breadcrumb-converter-crash
Jun 25, 2026
Merged

fix(replay): Guard against non-dictionary touch breadcrumb path elements#6346
antonis merged 2 commits into
mainfrom
fix/replay-breadcrumb-converter-crash

Conversation

@antonis

@antonis antonis commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

📜 Description

Fixes a fatal NSInvalidArgumentException crash in RNSentryReplayBreadcrumbConverter (Session Replay on iOS):

-[__NSCFString objectForKey:]: unrecognized selector sent to instance

getTouchPathMessageFrom: iterated over a touch breadcrumb's path array and treated every element as an NSDictionary, only guarding against nil. When an element was a non-dictionary (e.g. an NSString), calling objectForKey: on it raised NSInvalidArgumentExceptionSIGABRT.

Two gaps are addressed:

  1. getTouchPathMessageFrom: — each element is now validated with isKindOfClass:[NSDictionary class] before any dictionary access (the same pattern already used in convertNavigation:).
  2. convertTouch: — now guards that path is an NSArray before use, matching the existing convertMultiClick: implementation. Previously a non-array path would crash on [path count] (NSString does not respond to count).

💡 Motivation and Context

Reported in #6342 — observed as a fatal crash in production on iOS with Session Replay enabled (RN 0.81.5, Expo SDK 54, New Architecture + Hermes). The malformed touch-path element bypassed all existing guards.

Closes #6342

💚 How did you test it?

Added unit tests to RNSentryReplayBreadcrumbConverterTests.swift that reproduce the crash and assert it no longer occurs:

  • testTouchMessageReturnsNilOnNonDictionaryPathElement — the exact reported case (a string element).
  • testTouchMessageReturnsNilWhenAnyPathElementIsNotADictionary — non-dict element mixed with valid dicts.
  • testConvertTouchBreadcrumbWithNonDictionaryPathElementDoesNotCrash — exercised end-to-end via convert(from:).
  • testConvertTouchBreadcrumbWithNonArrayPathDoesNotCrash — non-array path.

These crash on the previous code and pass with the fix. Ran clang-format on the modified ObjC file.

📝 Checklist

  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPii is enabled.
  • I updated the docs if needed.
  • All tests passing.
  • No breaking changes.

🔮 Next steps

None.

Fixes a fatal NSInvalidArgumentException
(-[__NSCFString objectForKey:]: unrecognized selector) in
RNSentryReplayBreadcrumbConverter when a touch breadcrumb path
contains a non-dictionary element.

- getTouchPathMessageFrom: now validates each element with
  isKindOfClass:[NSDictionary class] before calling objectForKey:.
- convertTouch: now guards that `path` is an NSArray, matching
  convertMultiClick:.

Closes #6342

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

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


  • fix(replay): Guard against non-dictionary touch breadcrumb path elements by antonis in #6346
  • chore(deps): update Cocoa SDK to v9.19.0 by github-actions in #6343
  • chore(deps): update Android SDK to v8.45.0 by github-actions in #6344
  • fix(core): Align SENTRY_ENVIRONMENT/RELEASE/DIST in JS bundled options with native SDKs by antonis in #6330
  • chore(deps): update JavaScript SDK to v10.60.0 by github-actions in #6332
  • chore(core): Bump react-native and metro devDependencies to 0.86.0 by antonis in #6316
  • chore: Bump macOS sample to react-native-macos 0.81.7 by antonis in #6315
  • chore(e2e): Bump react-native devDependency to 0.86.0 by antonis in #6313
  • fix(core): Forward user geo as an object so the native scope keeps it by antonis in #6309
  • fix(ios): Remove manual geo handling, use sentry-cocoa native support by antonis in #6289
  • fix(deps): bump js-yaml from ^4.1.1 to ^4.2.0 by antonis in #6298
  • fix: update React Native repo URL to new GitHub org by antonis in #6290
  • chore(deps): update JavaScript SDK to v10.59.0 by github-actions in #6321
  • chore(deps): bump concurrent-ruby from 1.3.6 to 1.3.7 in /samples/react-native-macos by dependabot in #6327
  • chore(deps): bump undici from 6.24.1 to 6.27.0 by dependabot in #6328
  • chore(deps): bump actions/checkout from 6.0.3 to 7.0.0 by dependabot in #6324
  • fix(ios): [RN 0.87] remove unused React/RCTTextView.h import by cortinico in #6322
  • chore(deps): bump actions/setup-java from 5.2.0 to 5.3.0 by dependabot in #6326
  • chore(deps): bump ruby/setup-ruby from 1.313.0 to 1.314.0 by dependabot in #6325
  • chore(deps): update Android SDK to v8.44.1 by github-actions in #6323

🤖 This preview updates automatically when you update the PR.

@antonis antonis added the ready-to-merge Triggers the full CI test suite label Jun 25, 2026
Comment thread CHANGELOG.md Outdated
@sentry

sentry Bot commented Jun 25, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
Sentry RN io.sentry.reactnative.sample 8.15.1 (93) Release

⚙️ sentry-react-native Build Distribution Settings

@github-actions

Copy link
Copy Markdown
Contributor

iOS (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 3851.98 ms 1227.34 ms -2624.64 ms
Size 4.98 MiB 6.50 MiB 1.53 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
d038a14+dirty 3845.71 ms 1228.11 ms -2617.59 ms
41d6254+dirty 3845.71 ms 1224.51 ms -2621.20 ms
4966363+dirty 3854.04 ms 1231.55 ms -2622.50 ms
c004dae+dirty 3850.32 ms 1227.79 ms -2622.53 ms
eb93136+dirty 3843.09 ms 1220.11 ms -2622.98 ms
71abba0+dirty 3821.93 ms 1202.81 ms -2619.12 ms
ad66da3+dirty 3820.96 ms 1214.43 ms -2606.52 ms
ca9d079+dirty 3835.63 ms 1218.68 ms -2616.95 ms
df5d108+dirty 1225.90 ms 1220.14 ms -5.76 ms
4b87b12+dirty 1212.90 ms 1222.09 ms 9.19 ms

App size

Revision Plain With Sentry Diff
d038a14+dirty 5.15 MiB 6.67 MiB 1.51 MiB
41d6254+dirty 5.15 MiB 6.70 MiB 1.54 MiB
4966363+dirty 5.15 MiB 6.68 MiB 1.53 MiB
c004dae+dirty 5.15 MiB 6.67 MiB 1.51 MiB
eb93136+dirty 5.15 MiB 6.69 MiB 1.53 MiB
71abba0+dirty 5.15 MiB 6.67 MiB 1.52 MiB
ad66da3+dirty 5.15 MiB 6.67 MiB 1.51 MiB
ca9d079+dirty 5.15 MiB 6.69 MiB 1.53 MiB
df5d108+dirty 3.38 MiB 4.73 MiB 1.35 MiB
4b87b12+dirty 3.38 MiB 4.77 MiB 1.39 MiB

@antonis antonis marked this pull request as ready for review June 25, 2026 08:42
@github-actions

Copy link
Copy Markdown
Contributor

iOS (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 3838.02 ms 1219.49 ms -2618.53 ms
Size 4.98 MiB 6.50 MiB 1.53 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
d038a14+dirty 3831.11 ms 1216.30 ms -2614.81 ms
41d6254+dirty 3849.78 ms 1233.91 ms -2615.86 ms
4966363+dirty 3863.07 ms 1227.19 ms -2635.88 ms
c004dae+dirty 3857.82 ms 1224.87 ms -2632.95 ms
eb93136+dirty 3846.51 ms 1226.13 ms -2620.39 ms
71abba0+dirty 3852.70 ms 1224.53 ms -2628.16 ms
ad66da3+dirty 3855.02 ms 1213.43 ms -2641.59 ms
ca9d079+dirty 3818.62 ms 1216.72 ms -2601.90 ms
df5d108+dirty 1207.34 ms 1210.50 ms 3.16 ms
4b87b12+dirty 1199.49 ms 1199.78 ms 0.29 ms

App size

Revision Plain With Sentry Diff
d038a14+dirty 5.15 MiB 6.67 MiB 1.51 MiB
41d6254+dirty 5.15 MiB 6.70 MiB 1.54 MiB
4966363+dirty 5.15 MiB 6.68 MiB 1.53 MiB
c004dae+dirty 5.15 MiB 6.67 MiB 1.51 MiB
eb93136+dirty 5.15 MiB 6.69 MiB 1.53 MiB
71abba0+dirty 5.15 MiB 6.67 MiB 1.52 MiB
ad66da3+dirty 5.15 MiB 6.67 MiB 1.51 MiB
ca9d079+dirty 5.15 MiB 6.69 MiB 1.53 MiB
df5d108+dirty 3.38 MiB 4.73 MiB 1.35 MiB
4b87b12+dirty 3.38 MiB 4.77 MiB 1.39 MiB

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

Looks good to me

@antonis antonis merged commit 3ba1463 into main Jun 25, 2026
115 of 117 checks passed
@antonis antonis deleted the fix/replay-breadcrumb-converter-crash branch June 25, 2026 11:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Triggers the full CI test suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Session Replay: fatal NSInvalidArgumentException in RNSentryReplayBreadcrumbConverter (objectForKey: on non-dictionary touch-path element)

2 participants