fix(core): Attach debug_meta to Hermes JS error events via Debug ID lookup - #6545
Conversation
…ookup Error events relied on the core applyDebugIds path, which re-parses the Metro-injected premodule Error().stack and requires an exact filename match against the exception frames. That match is fragile for Hermes premodule stacks, so events frequently shipped without debug_meta and symbolication fell back to release + filename matching (broken for Expo OTA updates that keep the native release). Add a debugMetaIntegration that reuses profiling's direct Debug ID lookup (getDebugMetadata) to stamp debug_meta.images for error events. It backs off when core already matched the stack (frame.debug_id set) to avoid emitting a duplicate image, and dedupes defensively. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Semver Impact of This PR⚪ None (no version bump detected) 📋 Changelog PreviewThis is how your changes will appear in the changelog.
Plus 17 more 🤖 This preview updates automatically when you update the PR. |
073c8a0 to
f40d5e0
Compare
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@sentry review |
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 3b10f42. Configure here.
📲 Install BuildsAndroid
|
iOS (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| ecf47a2+dirty | 3835.20 ms | 1222.43 ms | -2612.77 ms |
| 3817909+dirty | 1183.90 ms | 1187.50 ms | 3.60 ms |
| 5ee78d6+dirty | 3847.52 ms | 1224.27 ms | -2623.25 ms |
| 890d145+dirty | 1223.59 ms | 1231.37 ms | 7.78 ms |
| e763471+dirty | 3841.16 ms | 1218.06 ms | -2623.09 ms |
| 3d31fcf+dirty | 3838.09 ms | 1223.46 ms | -2614.63 ms |
| 9210ae6+dirty | 3815.93 ms | 1214.14 ms | -2601.79 ms |
| 26843eb+dirty | 3861.60 ms | 1238.77 ms | -2622.82 ms |
| 7a89652+dirty | 3861.46 ms | 1229.61 ms | -2631.85 ms |
| 9ad4522+dirty | 3850.40 ms | 1222.40 ms | -2628.00 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| ecf47a2+dirty | 4.98 MiB | 6.46 MiB | 1.49 MiB |
| 3817909+dirty | 3.38 MiB | 4.73 MiB | 1.35 MiB |
| 5ee78d6+dirty | 5.15 MiB | 6.69 MiB | 1.53 MiB |
| 890d145+dirty | 3.38 MiB | 4.77 MiB | 1.38 MiB |
| e763471+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
| 3d31fcf+dirty | 4.98 MiB | 6.56 MiB | 1.58 MiB |
| 9210ae6+dirty | 5.15 MiB | 6.68 MiB | 1.53 MiB |
| 26843eb+dirty | 4.98 MiB | 6.53 MiB | 1.55 MiB |
| 7a89652+dirty | 5.15 MiB | 6.70 MiB | 1.55 MiB |
| 9ad4522+dirty | 4.98 MiB | 6.56 MiB | 1.58 MiB |
Previous results on branch: fix/6480-debug-meta-hermes
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 384cb83+dirty | 3856.39 ms | 1219.55 ms | -2636.84 ms |
| 088b29e+dirty | 3867.30 ms | 1221.30 ms | -2646.00 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 384cb83+dirty | 4.98 MiB | 6.56 MiB | 1.58 MiB |
| 088b29e+dirty | 4.98 MiB | 6.56 MiB | 1.58 MiB |
iOS (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 71abba0+dirty | 3852.70 ms | 1224.53 ms | -2628.16 ms |
| bc0d8cf+dirty | 3834.64 ms | 1223.91 ms | -2610.73 ms |
| 68ae91b+dirty | 3836.36 ms | 1222.04 ms | -2614.32 ms |
| 267d3ed+dirty | 3860.14 ms | 1223.39 ms | -2636.76 ms |
| f170ec3+dirty | 3844.74 ms | 1222.67 ms | -2622.07 ms |
| b9bebee+dirty | 3858.02 ms | 1231.92 ms | -2626.11 ms |
| d038a14+dirty | 3831.11 ms | 1216.30 ms | -2614.81 ms |
| 853723c+dirty | 3849.33 ms | 1221.07 ms | -2628.26 ms |
| e763471+dirty | 3826.10 ms | 1221.52 ms | -2604.58 ms |
| 3d31fcf+dirty | 3857.46 ms | 1237.17 ms | -2620.29 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 71abba0+dirty | 5.15 MiB | 6.67 MiB | 1.52 MiB |
| bc0d8cf+dirty | 5.15 MiB | 6.67 MiB | 1.51 MiB |
| 68ae91b+dirty | 4.98 MiB | 6.46 MiB | 1.48 MiB |
| 267d3ed+dirty | 5.15 MiB | 6.69 MiB | 1.54 MiB |
| f170ec3+dirty | 5.15 MiB | 6.69 MiB | 1.53 MiB |
| b9bebee+dirty | 5.15 MiB | 6.68 MiB | 1.53 MiB |
| d038a14+dirty | 5.15 MiB | 6.67 MiB | 1.51 MiB |
| 853723c+dirty | 5.15 MiB | 6.69 MiB | 1.53 MiB |
| e763471+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
| 3d31fcf+dirty | 4.98 MiB | 6.56 MiB | 1.58 MiB |
Previous results on branch: fix/6480-debug-meta-hermes
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 384cb83+dirty | 3844.38 ms | 1221.17 ms | -2623.21 ms |
| 088b29e+dirty | 3851.37 ms | 1214.07 ms | -2637.30 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 384cb83+dirty | 4.98 MiB | 6.56 MiB | 1.58 MiB |
| 088b29e+dirty | 5.08 MiB | 6.68 MiB | 1.60 MiB |
Android (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 27d9693+dirty | 419.08 ms | 469.12 ms | 50.04 ms |
| 04207c4+dirty | 459.19 ms | 518.54 ms | 59.35 ms |
| 8929511+dirty | 405.33 ms | 452.16 ms | 46.83 ms |
| eb93136+dirty | 416.18 ms | 467.32 ms | 51.14 ms |
| c004dae+dirty | 412.86 ms | 481.50 ms | 68.64 ms |
| 3b6e9f9+dirty | 442.70 ms | 486.44 ms | 43.74 ms |
| 0bd8916+dirty | 412.77 ms | 451.31 ms | 38.54 ms |
| bc8f61e+dirty | 442.98 ms | 506.56 ms | 63.58 ms |
| 7d8c8bd+dirty | 417.45 ms | 462.10 ms | 44.65 ms |
| a0d8cf8+dirty | 411.71 ms | 467.57 ms | 55.87 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 27d9693+dirty | 49.74 MiB | 55.09 MiB | 5.34 MiB |
| 04207c4+dirty | 43.75 MiB | 48.12 MiB | 4.37 MiB |
| 8929511+dirty | 43.75 MiB | 48.16 MiB | 4.41 MiB |
| eb93136+dirty | 48.30 MiB | 53.58 MiB | 5.28 MiB |
| c004dae+dirty | 48.30 MiB | 53.49 MiB | 5.19 MiB |
| 3b6e9f9+dirty | 48.30 MiB | 53.54 MiB | 5.23 MiB |
| 0bd8916+dirty | 48.30 MiB | 53.57 MiB | 5.26 MiB |
| bc8f61e+dirty | 49.74 MiB | 55.09 MiB | 5.35 MiB |
| 7d8c8bd+dirty | 48.30 MiB | 53.54 MiB | 5.23 MiB |
| a0d8cf8+dirty | 48.30 MiB | 53.49 MiB | 5.19 MiB |
Previous results on branch: fix/6480-debug-meta-hermes
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 384cb83+dirty | 423.51 ms | 487.04 ms | 63.53 ms |
| 088b29e+dirty | 488.18 ms | 529.24 ms | 41.06 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 384cb83+dirty | 49.74 MiB | 55.38 MiB | 5.64 MiB |
| 088b29e+dirty | 49.74 MiB | 55.44 MiB | 5.70 MiB |
Android (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 27d9693+dirty | 438.63 ms | 514.08 ms | 75.46 ms |
| 68672fc+dirty | 407.55 ms | 442.96 ms | 35.41 ms |
| 15d4514+dirty | 413.63 ms | 449.62 ms | 35.99 ms |
| 882f8ae+dirty | 408.19 ms | 435.86 ms | 27.67 ms |
| bc8f61e+dirty | 419.31 ms | 453.39 ms | 34.08 ms |
| 21a1e70+dirty | 437.55 ms | 507.10 ms | 69.56 ms |
| 4acd4e9+dirty | 431.33 ms | 477.68 ms | 46.35 ms |
| 20fbd51+dirty | 594.38 ms | 655.35 ms | 60.97 ms |
| 5a316ea+dirty | 626.41 ms | 645.00 ms | 18.59 ms |
| ecf47a2+dirty | 457.21 ms | 498.10 ms | 40.89 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 27d9693+dirty | 49.74 MiB | 55.09 MiB | 5.34 MiB |
| 68672fc+dirty | 48.30 MiB | 53.61 MiB | 5.31 MiB |
| 15d4514+dirty | 48.30 MiB | 53.60 MiB | 5.30 MiB |
| 882f8ae+dirty | 48.30 MiB | 53.60 MiB | 5.29 MiB |
| bc8f61e+dirty | 49.74 MiB | 55.09 MiB | 5.35 MiB |
| 21a1e70+dirty | 49.74 MiB | 54.82 MiB | 5.07 MiB |
| 4acd4e9+dirty | 49.74 MiB | 55.26 MiB | 5.52 MiB |
| 20fbd51+dirty | 49.74 MiB | 54.81 MiB | 5.07 MiB |
| 5a316ea+dirty | 49.74 MiB | 55.09 MiB | 5.34 MiB |
| ecf47a2+dirty | 49.74 MiB | 54.82 MiB | 5.07 MiB |
Previous results on branch: fix/6480-debug-meta-hermes
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 384cb83+dirty | 425.08 ms | 477.16 ms | 52.08 ms |
| 088b29e+dirty | 444.83 ms | 478.30 ms | 33.47 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 384cb83+dirty | 49.74 MiB | 55.38 MiB | 5.64 MiB |
| 088b29e+dirty | 49.74 MiB | 55.44 MiB | 5.70 MiB |
| return event; | ||
| } | ||
|
|
||
| event.debug_meta = event.debug_meta || {}; |
There was a problem hiding this comment.
| event.debug_meta = event.debug_meta || {}; | |
| event.debug_meta ??= {}; |
Instructions and example for changelogPlease add an entry to Example: ## Unreleased
### Fixes
- Attach debug_meta to Hermes JS error events via Debug ID lookup ([#6545](https://github.com/getsentry/sentry-react-native/pull/6545))If none of the above apply, you can opt out of this check by adding |
📢 Type of change
📜 Description
On React Native + Hermes (including Expo OTA /
expo exportHermes bundles), plain JS exception events often ship withoutdebug_meta.images, even when Metro injected the Debug ID premodule (_sentryDebugIds) and the matching artifact bundle was uploaded with that Debug ID.The core
prepareEventpipeline attempts this viaapplyDebugIds→applyDebugMeta, but that path re-parses the premoduleError().stackand requires an exact filename match against the exception frames. That match is fragile for Hermes premodule stacks, sofilenameDebugIdMapends up empty and nodebug_metais attached.Profiling already solves the same problem robustly via
getDebugMetadata()(profiling/debugid.ts): it reads_sentryDebugIdsdirectly and stamps a singlesourcemapimage with the canonical bundlecode_file(app:///index.android.bundle/app:///main.jsbundle) — no stack reparse. That helper was not wired into the error event pipeline.This PR adds a default
debugMetaIntegrationthat reusesgetDebugMetadata()to stampdebug_meta.imageson error events. Key details:event.type === undefined) — transactions, profiles and other event types are untouched.applyDebugIds(setsframe.debug_id) before event processors andapplyDebugMeta(stamps images) after them. The integration detects a successful core match viaframe.debug_idand backs off, so core's own stamp is not duplicated. When core fails to match (the bug case), the integration fills the gap.debug_id, and preserves unrelated pre-existing images (e.g. native images added bynativeLinkedErrors).createReactNativeRewriteFrames()so the canonical bundle filename is already in place.💡 Motivation and Context
Without
debug_meta, backends fall back to release + filename matching. RN/Expo rewrites every JS frame to the same canonical filename, and OTA updates keep the native release, so the native build's Hermes map can be applied to OTA bytecode → wrong files/lines. The missingdebug_metais an SDK-side gap regardless of backend.Fixes #6480
💚 How did you test it?
test/integrations/debugmeta.test.tscovering: stamping on error events, no-op when no Debug ID, skipping non-error events, backing off when core matched, and preserving pre-existing images.prepareEventordering (applyDebugIds→ event processor →applyDebugMeta) and assert exactly one image results whether core succeeds or fails — guarding against a duplicate-image regression.debugMetaIntegration.📝 Checklist
sendDefaultPIIis enabled.🔮 Next steps
debugMetaIntegration) — the mechanism is RN/Hermes-specific (single bundle per platform); a more specific name could be used if preferred.🤖 Generated with Claude Code