Repository navigation
fix: Screenshots not being captured by hybrid SDKs - #8578
Merged
Merged
Conversation
`SentryDependencyContainer.screenshotSource` was a `lazy var` wrapping `getOptionalLazyVar`. `getOptionalLazyVar` retries its builder until the value can be produced, but the `lazy var` defeated that by caching the first result. The builder returns nil when `startOptions` isn't set yet, so if screenshotSource was first accessed before the SDK started — which hybrid SDKs do when they touch `SentrySDK.internal` before `SentrySDK.start` — the nil was cached permanently and no screenshot could be captured for the rest of the process. Change screenshotSource to a computed property so getOptionalLazyVar re-runs the builder until startOptions is available, then caches the built source. Keep the setter (a `lazy var` was settable; tests inject a mock). Add a regression test. Tracked by getsentry/sentry-react-native#6507; regression reported in getsentry/sentry-react-native#6497. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
antonis
force-pushed
the
fix/screenshot-source-not-captured-hybrid-sdks
branch
from
July 27, 2026 12:46
f4daf34 to
a023a20
Compare
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit a023a20. Configure here.
📲 Install BuildsiOS
|
Contributor
Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| ce33dcf | 1236.42 ms | 1267.76 ms | 31.34 ms |
| 0a8fa8a | 1230.72 ms | 1261.64 ms | 30.91 ms |
| 4455127 | 1216.29 ms | 1250.00 ms | 33.71 ms |
| 4e7765a | 1230.37 ms | 1265.84 ms | 35.47 ms |
| b557385 | 1211.45 ms | 1252.67 ms | 41.22 ms |
| 3efa7b5 | 1226.55 ms | 1260.66 ms | 34.11 ms |
| 0303c4f | 1229.73 ms | 1264.79 ms | 35.06 ms |
| 8469478 | 1240.30 ms | 1277.07 ms | 36.76 ms |
| bbc91e5 | 1215.94 ms | 1243.26 ms | 27.32 ms |
| 5bcf269 | 1223.60 ms | 1245.49 ms | 21.89 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| ce33dcf | 24.14 KiB | 1.19 MiB | 1.16 MiB |
| 0a8fa8a | 24.14 KiB | 1.18 MiB | 1.15 MiB |
| 4455127 | 24.14 KiB | 1.24 MiB | 1.21 MiB |
| 4e7765a | 24.14 KiB | 1.24 MiB | 1.22 MiB |
| b557385 | 24.14 KiB | 1.23 MiB | 1.20 MiB |
| 3efa7b5 | 24.14 KiB | 1.22 MiB | 1.19 MiB |
| 0303c4f | 24.14 KiB | 1.24 MiB | 1.21 MiB |
| 8469478 | 24.14 KiB | 1.24 MiB | 1.21 MiB |
| bbc91e5 | 24.14 KiB | 1.17 MiB | 1.14 MiB |
| 5bcf269 | 24.14 KiB | 1.17 MiB | 1.15 MiB |
antonis
marked this pull request as ready for review
July 27, 2026 13:34
antonis
requested review from
NinjaLikesCheez,
itaybre,
noahsmartin,
philippsuess and
philprime
as code owners
July 27, 2026 13:34
NinjaLikesCheez
approved these changes
Jul 27, 2026
Contributor
Instructions and example for changelogPlease add an entry to Example: ## Unreleased
### Fixes
- Screenshots not being captured by hybrid SDKs ([#8578](https://github.com/getsentry/sentry-cocoa/pull/8578))If none of the above apply, you can opt out of this check by adding |
7 of 11 tasks
alwx
added a commit
to getsentry/sentry-react-native
that referenced
this pull request
Aug 3, 2026
Reapplies #6380 (reverted in 8.20.0 by #6491) now that the underlying sentry-cocoa bug is fixed. #6380 migrated the iOS code off the deprecated PrivateSentrySDKOnly SPI onto the SentrySDK.internal Swift API. It shipped in 8.19.0 and broke every iOS screenshot (Feedback Widget screenshot, attachScreenshot, Sentry.captureScreenshot) — #6497. Root cause was in sentry-cocoa: constructing SentryInternalApi eagerly reads SentryDependencyContainer.screenshotSource, a lazy var whose builder returns nil while startOptions is unset. Being lazy, that nil was cached for the process lifetime, and RN reads SentrySDK.internal before SentrySDK.start (from RNSentryStart, and from JS integrations calling fetchNativeAppStart / fetchNativeSdkInfo during init). getsentry/sentry-cocoa#8578 makes screenshotSource a computed property so the builder re-runs until startOptions is available; it shipped in 9.24.0, which this bumps to. Adds RNSentryScreenshotSourceTests as a regression guard: it reads SentrySDK.internal before starting the SDK and asserts screenshot capture still works. Verified to fail against 9.19.1 and pass against 9.24.0. RNSentry+fetchNativeStack.m was the last production file still reading options through the hand-rolled SentrySDKInternal redeclaration in RNSentry.h. It now goes through SentrySDKWrapper.debug like the rest of RNSentry.mm, and the redeclaration is gone. Re-landing also restores the two improvements the revert removed: the fetchViewHierarchy nil-guard (returns null instead of a zero-byte attachment on capture failure) and the RNSentryTimeToDisplay extern linkage. Fixes #6507.
3 tasks
alwx
added a commit
to getsentry/sentry-react-native
that referenced
this pull request
Aug 7, 2026
…4.0 (#6541) * fix(ios): Re-land SentrySDK.internal migration, bump Cocoa SDK to 9.24.0 Reapplies #6380 (reverted in 8.20.0 by #6491) now that the underlying sentry-cocoa bug is fixed. #6380 migrated the iOS code off the deprecated PrivateSentrySDKOnly SPI onto the SentrySDK.internal Swift API. It shipped in 8.19.0 and broke every iOS screenshot (Feedback Widget screenshot, attachScreenshot, Sentry.captureScreenshot) — #6497. Root cause was in sentry-cocoa: constructing SentryInternalApi eagerly reads SentryDependencyContainer.screenshotSource, a lazy var whose builder returns nil while startOptions is unset. Being lazy, that nil was cached for the process lifetime, and RN reads SentrySDK.internal before SentrySDK.start (from RNSentryStart, and from JS integrations calling fetchNativeAppStart / fetchNativeSdkInfo during init). getsentry/sentry-cocoa#8578 makes screenshotSource a computed property so the builder re-runs until startOptions is available; it shipped in 9.24.0, which this bumps to. Adds RNSentryScreenshotSourceTests as a regression guard: it reads SentrySDK.internal before starting the SDK and asserts screenshot capture still works. Verified to fail against 9.19.1 and pass against 9.24.0. RNSentry+fetchNativeStack.m was the last production file still reading options through the hand-rolled SentrySDKInternal redeclaration in RNSentry.h. It now goes through SentrySDKWrapper.debug like the rest of RNSentry.mm, and the redeclaration is gone. Re-landing also restores the two improvements the revert removed: the fetchViewHierarchy nil-guard (returns null instead of a zero-byte attachment on capture failure) and the RNSentryTimeToDisplay extern linkage. Fixes #6507. * fix(ios): Drop the dead CocoaPods source-build fallback The `sentry-consumption: cocoapods` sample build failed on this branch with "None of your spec sources contain a spec satisfying the dependency: Sentry (= 9.24.0)". sentry-cocoa deleted `Sentry.podspec` and removed the `cocoapods` craft publishing target in 9.20.0, so 9.19.1 is the last version ever pushed to the CocoaPods trunk (verified: trunk serves 9.19.1 but 404s on 9.24.0). That makes `SENTRY_USE_XCFRAMEWORK=0` -> `s.dependency 'Sentry', <version>` unresolvable for every version this SDK will ship from now on. A podspec cannot point `s.dependency` at a git source, so the fallback cannot be repaired. It stayed green on main only because main still pins 9.19.1. Replace the fallback with a raise explaining why it is gone and pointing at SENTRY_XCFRAMEWORK_CACHE_DIR for builds without GitHub Releases access, and drop the CI matrix entry that exercised it. Also apply review feedback on the changelog: move the entry to the top of Unreleased and turn the modular-headers note into a [!WARNING] callout so RN < 0.75 users see the required Podfile change immediately.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📜 Description
SentryDependencyContainer.screenshotSourcewas alazy varwrappinggetOptionalLazyVar.getOptionalLazyVaris designed to retry its builder until the value can be produced, but thelazy vardefeats that: it runs the initializer once and caches whatever the first access returned. The builder returnsnilwhenstartOptionsisn't set yet, so ifscreenshotSourceis first read before the SDK is started, thatnilgets cached permanently and no screenshot can be captured for the rest of the process.This changes
screenshotSourcefrom alazy varto a computed property sogetOptionalLazyVarre-runs the builder untilstartOptionsis available, then caches the built source. The setter is kept (alazy varwas settable, and tests inject a mock source). Adds a regression test.💡 Motivation and Context
Hybrid SDKs touch
SentrySDK.internalbeforeSentrySDK.start(e.g. React Native reads SDK metadata / app-start data during init). ConstructingSentrySDK.internaleagerly readsscreenshotSource, which poisoned thelazy varand broke all screenshot capture on iOS — Feedback Widget screenshots,attachScreenshot, andSentrySDK.internal.screenshot.capture(). This shipped as a regression in sentry-react-native 8.19.0.This is the sentry-cocoa fix tracked by getsentry/sentry-react-native#6507**.** That issue reverted the RN migration (getsentry/sentry-react-native#6380) as an interim fix; once this cocoa change ships and RN bumps the cocoa dependency, the RN migration will be reapplied.
💚 How did you test it?
Added
testScreenshotSource_AccessedBeforeStartOptions_RebuildsAfterStart, which reproduces the sequence: readscreenshotSourcebeforestartOptionsis set (→nil, and must not be cached), set options, then assert it's rebuilt (non-nil). It fails on the oldlazy varand passes with the fix.Ran on the iOS 18.6 simulator across
SentryDependencyContainerTests,SentryScreenshotIntegrationTests,SentryScreenshotSourceTests, andUserFeedbackIntegrationTests— all passing.📝 Checklist
sendDefaultPIIis enabled.🤖 Generated with Claude Code