Skip to content

fix(core): Strip callback options before the native SDK starts - #6847

Merged
alwx merged 2 commits into
mainfrom
alwx/bugfix/6842
Oct 6, 2026
Merged

alwx merged 2 commits into
mainfrom
alwx/bugfix/6842

Conversation

@alwx

@alwx alwx commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

📢 Type of change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring

📜 Description

A JS function crosses the bridge as a native callback that only accepts an NSArray *. initNativeSdk removed a fixed list of callback names, but it did not remove beforeSendLog or beforeSendSpan. sentry-cocoa reads beforeSendLog from the options dictionary and calls it with a SentryLog, which crashes the app. The SDK now removes every function value from the options before it starts the native SDK.

💡 Motivation and Context

Fixes #6842. A fixed list of names goes stale each time the JavaScript SDK adds a new callback option, so the new filter works by value type instead.

💚 How did you test it?

Added unit tests for beforeSendLog, for beforeSendSpan, and for the general rule that no function reaches initNativeSdk. Ran yarn test, yarn lint, yarn circularDepCheck, and yarn api-report:check.

📝 Checklist

  • I added tests to verify changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • All tests passing.
  • Public API changes reviewed by another Mobile SDK team member or implemented according to the develop docs spec.
  • No breaking changes.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 6, 2026

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(core): Strip callback options before the native SDK starts by alwx in #6847
  • fix(android): Resolve @sentry/react-native from rootDir in Expo plugin by alwx in #6840
  • chore: Clean up non-actionable TODOs by antonis in #6843
  • chore(deps): update JavaScript SDK to v10.76.0 by antonis in #6831
  • chore(expo): bump sample to Expo 57.0.26 by antonis in #6838
  • chore(deps): Bump basic-ftp to 6.2.2 by alwx in #6837
  • fix(core): Mark package as side-effect free by devclaimjuimperai in #6829
  • chore(deps): bump getsentry/craft/.github/workflows/changelog-preview.yml from 2.31.0 to 2.33.1 by dependabot in #6833
  • chore(deps): bump gradle/actions/setup-gradle from 6.3.0 to 6.4.0 by dependabot in #6834
  • chore(deps): bump getsentry/craft from 2.31.2 to 2.33.1 by dependabot in #6835
  • chore(deps): bump getsentry/github-workflows/validate-pr from 4013fc6e1aeb1be1f9d3b4d232624f0ec1afa613 to 36c729264d2edc29ebae61950c50e1e9f043ad7e by dependabot in #6832
  • fix(android): Settle initNativeReactNavigationNewFrameTracking promise by antonis in #6823
  • fix(spotlight): Forward image attachments to Spotlight by antonis in #6818
  • fix(ios): Prevent crash when initialized with an invalid DSN by antonis in #6825
  • chore(core): Resolve non-actionable TODOs by antonis in #6826
  • chore(core): resolve stale TODO comments by antonis in #6819
  • fix(profiling): Populate Hermes runtime version on JS profiles by antonis in #6817

🤖 This preview updates automatically when you update the PR.

alwx and others added 2 commits October 6, 2026 11:12
A JS function crosses the bridge as a native callback that only accepts an
array. sentry-cocoa reads `beforeSendLog` from the options dictionary and calls
it with a `SentryLog`, which crashes the app.

Remove every function value from the options before `initNativeSdk`, instead of
a fixed list of names. This also covers `beforeSendSpan` and any callback the
JavaScript SDK adds later.

Fixes #6842

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@alwx
alwx force-pushed the alwx/bugfix/6842 branch from 69c99bc to 469b756 Compare October 6, 2026 09:14
@alwx
alwx marked this pull request as ready for review October 6, 2026 09:25
Comment on lines 331 to 341
// filter out all the options that would crash native.
/* oxlint-disable typescript-eslint(no-unused-vars) */
const {
beforeSend,
beforeBreadcrumb,
beforeSendTransaction,
beforeSendMetric,
integrations,
ignoreErrors,
logsOrigin,
profilingOptions,
androidProfilingOptions,
onNativeLog,
...filteredOptions
} = options;
const { integrations, ignoreErrors, logsOrigin, profilingOptions, androidProfilingOptions, ...remainingOptions } =
options;
/* oxlint-enable typescript-eslint(no-unused-vars) */

const filteredOptions = withoutFunctionValues(remainingOptions);

// Move profilingOptions into _experiments
// Support deprecated androidProfilingOptions for backwards compatibility
const resolvedProfilingOptions = profilingOptions ?? androidProfilingOptions;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The withoutFunctionValues function only performs a shallow filter, failing to remove functions from nested objects like mobileReplayOptions, which can cause a native crash.
Severity: HIGH

Suggested Fix

Modify the withoutFunctionValues function to recursively traverse the options object and remove any nested functions. This will ensure that objects like mobileReplayOptions are properly sanitized before being passed to the native bridge.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: packages/core/src/js/wrapper.ts#L330-L341

Potential issue: The `withoutFunctionValues` function is intended to strip function
properties from an options object before it's passed to the native layer. However, it
only performs a shallow filter. If an option like `mobileReplayOptions` is passed, which
is an object that can contain a function property like `beforeErrorSampling`, this
nested function is not removed. The `typeof` check for `mobileReplayOptions` returns
"object", so the entire object, including the nested function, is passed through. This
will cause a crash in the native SDK when it tries to process the function.

Did we get this right? 👍 / 👎 to inform future reviews.

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.

Sounds valid but I think it is preexisting

@antonis antonis added the ready-to-merge Triggers the full CI test suite label Oct 6, 2026

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

LGTM 🚀
Added the ready-to-merge label for a full CI check before merging.

@sentry

sentry Bot commented Oct 6, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

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

⚙️ sentry-react-native Build Distribution Settings

@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Android (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 428.59 ms 447.88 ms 19.29 ms
Size 50.56 MiB 56.59 MiB 6.03 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
0b5a379+dirty 472.78 ms 533.16 ms 60.38 ms
bf168a4+dirty 418.21 ms 489.74 ms 71.53 ms
1a2e7e0+dirty 416.61 ms 445.46 ms 28.85 ms
a2585ce+dirty 426.36 ms 483.26 ms 56.90 ms
4e0b819+dirty 420.56 ms 470.08 ms 49.52 ms
9c84b9a+dirty 520.74 ms 539.38 ms 18.64 ms
2c735cc+dirty 414.09 ms 438.47 ms 24.38 ms
5c1e987+dirty 423.52 ms 471.64 ms 48.12 ms
04207c4+dirty 459.19 ms 518.54 ms 59.35 ms
68ae91b+dirty 416.44 ms 477.56 ms 61.12 ms

App size

Revision Plain With Sentry Diff
0b5a379+dirty 48.30 MiB 53.58 MiB 5.28 MiB
bf168a4+dirty 49.74 MiB 55.09 MiB 5.35 MiB
1a2e7e0+dirty 49.74 MiB 54.82 MiB 5.07 MiB
a2585ce+dirty 49.74 MiB 55.36 MiB 5.61 MiB
4e0b819+dirty 49.74 MiB 54.81 MiB 5.07 MiB
9c84b9a+dirty 49.74 MiB 55.36 MiB 5.62 MiB
2c735cc+dirty 43.75 MiB 48.08 MiB 4.33 MiB
5c1e987+dirty 43.75 MiB 48.08 MiB 4.33 MiB
04207c4+dirty 43.75 MiB 48.12 MiB 4.37 MiB
68ae91b+dirty 49.74 MiB 54.79 MiB 5.05 MiB

@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

iOS (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 3871.22 ms 1236.35 ms -2634.88 ms
Size 5.15 MiB 6.94 MiB 1.79 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
8448c07+dirty 3820.88 ms 1217.17 ms -2603.71 ms
c1f3a96+dirty 3848.54 ms 1218.81 ms -2629.73 ms
44abcc2+dirty 3836.54 ms 1223.33 ms -2613.21 ms
e5bb5f6+dirty 3826.14 ms 1212.24 ms -2613.90 ms
df5d108+dirty 1225.90 ms 1220.14 ms -5.76 ms
1d3572b+dirty 3872.73 ms 1235.00 ms -2637.73 ms
ae37560+dirty 3832.10 ms 1219.09 ms -2613.02 ms
68672fc+dirty 3841.58 ms 1228.89 ms -2612.69 ms
f170ec3+dirty 3822.26 ms 1218.33 ms -2603.93 ms
ca9d079+dirty 3835.63 ms 1218.68 ms -2616.95 ms

App size

Revision Plain With Sentry Diff
8448c07+dirty 4.98 MiB 6.55 MiB 1.57 MiB
c1f3a96+dirty 5.15 MiB 6.87 MiB 1.72 MiB
44abcc2+dirty 4.98 MiB 6.55 MiB 1.57 MiB
e5bb5f6+dirty 4.98 MiB 6.51 MiB 1.53 MiB
df5d108+dirty 3.38 MiB 4.73 MiB 1.35 MiB
1d3572b+dirty 4.98 MiB 6.56 MiB 1.58 MiB
ae37560+dirty 5.15 MiB 6.70 MiB 1.54 MiB
68672fc+dirty 5.15 MiB 6.71 MiB 1.55 MiB
f170ec3+dirty 5.15 MiB 6.69 MiB 1.53 MiB
ca9d079+dirty 5.15 MiB 6.69 MiB 1.53 MiB

@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Android (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 464.31 ms 492.00 ms 27.69 ms
Size 50.56 MiB 56.59 MiB 6.03 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
7436d0f+dirty 429.58 ms 452.52 ms 22.94 ms
b0d3373+dirty 412.17 ms 452.84 ms 40.67 ms
7ac3378+dirty 410.67 ms 442.60 ms 31.92 ms
53a3f8e+dirty 422.00 ms 436.96 ms 14.96 ms
e763471+dirty 538.31 ms 574.44 ms 36.13 ms
c004dae+dirty 404.60 ms 430.67 ms 26.07 ms
bfba737+dirty 425.19 ms 465.98 ms 40.79 ms
f3215d3+dirty 396.53 ms 436.66 ms 40.13 ms
23598c3+dirty 371.92 ms 420.65 ms 48.74 ms
ad66da3+dirty 411.49 ms 449.38 ms 37.89 ms

App size

Revision Plain With Sentry Diff
7436d0f+dirty 48.30 MiB 53.60 MiB 5.30 MiB
b0d3373+dirty 48.30 MiB 53.58 MiB 5.28 MiB
7ac3378+dirty 43.94 MiB 48.99 MiB 5.05 MiB
53a3f8e+dirty 50.56 MiB 56.46 MiB 5.90 MiB
e763471+dirty 49.74 MiB 54.85 MiB 5.11 MiB
c004dae+dirty 48.30 MiB 53.49 MiB 5.19 MiB
bfba737+dirty 49.74 MiB 55.09 MiB 5.34 MiB
f3215d3+dirty 48.30 MiB 53.49 MiB 5.19 MiB
23598c3+dirty 43.94 MiB 49.02 MiB 5.08 MiB
ad66da3+dirty 48.30 MiB 53.49 MiB 5.19 MiB

@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

iOS (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 3866.04 ms 1230.81 ms -2635.23 ms
Size 5.15 MiB 6.94 MiB 1.79 MiB

@alwx
alwx merged commit 1236b6e into main Oct 6, 2026
126 of 132 checks passed
@alwx
alwx deleted the alwx/bugfix/6842 branch October 6, 2026 11:58
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.

iOS crash -[SentryLog count]: unrecognized selector when beforeSendLog is set and the native SDK emits a log

2 participants