Skip to content

fix: Screenshots not being captured by hybrid SDKs - #8578

Merged
itaybre merged 1 commit into
mainfrom
fix/screenshot-source-not-captured-hybrid-sdks
Jul 27, 2026
Merged

itaybre merged 1 commit into
mainfrom
fix/screenshot-source-not-captured-hybrid-sdks

Conversation

@antonis

@antonis antonis commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

📜 Description

SentryDependencyContainer.screenshotSource was a lazy var wrapping getOptionalLazyVar. getOptionalLazyVar is designed to retry its builder until the value can be produced, but the lazy var defeats that: it runs the initializer once and caches whatever the first access returned. The builder returns nil when startOptions isn't set yet, so if screenshotSource is first read before the SDK is started, that nil gets cached permanently and no screenshot can be captured for the rest of the process.

This changes screenshotSource from a lazy var to a computed property so getOptionalLazyVar re-runs the builder until startOptions is available, then caches the built source. The setter is kept (a lazy var was settable, and tests inject a mock source). Adds a regression test.

💡 Motivation and Context

Hybrid SDKs touch SentrySDK.internal before SentrySDK.start (e.g. React Native reads SDK metadata / app-start data during init). Constructing SentrySDK.internal eagerly reads screenshotSource, which poisoned the lazy var and broke all screenshot capture on iOS — Feedback Widget screenshots, attachScreenshot, and SentrySDK.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: read screenshotSource before startOptions is set (→ nil, and must not be cached), set options, then assert it's rebuilt (non-nil). It fails on the old lazy var and passes with the fix.

Ran on the iOS 18.6 simulator across SentryDependencyContainerTests, SentryScreenshotIntegrationTests, SentryScreenshotSourceTests, and UserFeedbackIntegrationTests — all passing.

📝 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.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.
  • Public API changes reviewed by another Mobile SDK team member or implemented according to the develop docs spec.
  • If I added a new public API, I also added it to the SentryObjC wrapper.

🤖 Generated with Claude Code

`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
antonis force-pushed the fix/screenshot-source-not-captured-hybrid-sdks branch from f4daf34 to a023a20 Compare July 27, 2026 12:46
@antonis antonis added the run-full-ci Allows gated GitHub Action workflows to run for a labelled pull request label Jul 27, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

@sentry

sentry Bot commented Jul 27, 2026

Copy link
Copy Markdown

📲 Install Builds

iOS

🔗 App Name App ID Version Configuration
SDK-Size io.sentry.sample.SDK-Size 9.23.0 (1) Release

⚙️ sentry-cocoa Build Distribution Settings

@github-actions

Copy link
Copy Markdown
Contributor

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1229.41 ms 1258.51 ms 29.10 ms
Size 24.14 KiB 1.25 MiB 1.23 MiB

Baseline results on branch: main

Startup times

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
antonis marked this pull request as ready for review July 27, 2026 13:34
@itaybre
itaybre merged commit a879c92 into main Jul 27, 2026
344 of 370 checks passed
@itaybre
itaybre deleted the fix/screenshot-source-not-captured-hybrid-sdks branch July 27, 2026 21:58
@github-actions

Copy link
Copy Markdown
Contributor
Fails
🚫 Please consider adding a changelog entry for the next release.

Instructions and example for changelog

Please add an entry to CHANGELOG.md to the "Unreleased" section. Make sure the entry includes this PR's number.

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 #skip-changelog to the PR description or adding a skip-changelog label.

Generated by 🚫 dangerJS against a023a20

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.
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved run-full-ci Allows gated GitHub Action workflows to run for a labelled pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants