Skip to content

fix(core): Attach debug_meta to Hermes JS error events via Debug ID lookup - #6545

Draft
antonis wants to merge 2 commits into
mainfrom
fix/6480-debug-meta-hermes
Draft

fix(core): Attach debug_meta to Hermes JS error events via Debug ID lookup#6545
antonis wants to merge 2 commits into
mainfrom
fix/6480-debug-meta-hermes

Conversation

@antonis

@antonis antonis commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

📢 Type of change

  • Bugfix

📜 Description

On React Native + Hermes (including Expo OTA / expo export Hermes bundles), plain JS exception events often ship without debug_meta.images, even when Metro injected the Debug ID premodule (_sentryDebugIds) and the matching artifact bundle was uploaded with that Debug ID.

The core prepareEvent pipeline attempts this via applyDebugIdsapplyDebugMeta, but that path re-parses the premodule Error().stack and requires an exact filename match against the exception frames. That match is fragile for Hermes premodule stacks, so filenameDebugIdMap ends up empty and no debug_meta is attached.

Profiling already solves the same problem robustly via getDebugMetadata() (profiling/debugid.ts): it reads _sentryDebugIds directly and stamps a single sourcemap image with the canonical bundle code_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 debugMetaIntegration that reuses getDebugMetadata() to stamp debug_meta.images on error events. Key details:

  • Scoped to error events (event.type === undefined) — transactions, profiles and other event types are untouched.
  • Idempotent against core. Core runs applyDebugIds (sets frame.debug_id) before event processors and applyDebugMeta (stamps images) after them. The integration detects a successful core match via frame.debug_id and backs off, so core's own stamp is not duplicated. When core fails to match (the bug case), the integration fills the gap.
  • Defensive dedupe by debug_id, and preserves unrelated pre-existing images (e.g. native images added by nativeLinkedErrors).
  • Registered right after 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 missing debug_meta is an SDK-side gap regardless of backend.

Fixes #6480

💚 How did you test it?

  • Added test/integrations/debugmeta.test.ts covering: stamping on error events, no-op when no Debug ID, skipping non-error events, backing off when core matched, and preserving pre-existing images.
  • Added tests that reproduce the core prepareEvent ordering (applyDebugIds → event processor → applyDebugMeta) and assert exactly one image results whether core succeeds or fails — guarding against a duplicate-image regression.
  • Regenerated the API report for the new public debugMetaIntegration.

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

🔮 Next steps

  • Confirm naming (debugMetaIntegration) — the mechanism is RN/Hermes-specific (single bundle per platform); a more specific name could be used if preferred.

🤖 Generated with Claude Code

…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>
@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(core): Attach debug_meta to Hermes JS error events via Debug ID lookup by antonis in #6545
  • chore(deps): update Sentry Android Gradle Plugin to v6.17.0 by github-actions in #6544
  • feat(core): Extend TurboModule instrumentation to legacy NativeModules by alwx in #6504
  • feat(ios): Introduce enableMetricKit option by alwx in #6540

🤖 This preview updates automatically when you update the PR.

@antonis
antonis force-pushed the fix/6480-debug-meta-hermes branch from 073c8a0 to f40d5e0 Compare July 30, 2026 15:51
@antonis antonis added the ready-to-merge Triggers the full CI test suite label Jul 30, 2026
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@antonis

antonis commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

@sentry review

@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 3b10f42. Configure here.

@sentry

sentry Bot commented Jul 30, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

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

⚙️ sentry-react-native Build Distribution Settings

@github-actions

Copy link
Copy Markdown
Contributor

iOS (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 3856.39 ms 1219.55 ms -2636.84 ms
Size 4.98 MiB 6.56 MiB 1.58 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
2cac31b+dirty 3886.27 ms 1230.85 ms -2655.42 ms
244f6e8+dirty 3833.36 ms 1212.96 ms -2620.41 ms
61cc206+dirty 3849.70 ms 1230.33 ms -2619.38 ms
04207c4+dirty 1191.27 ms 1189.78 ms -1.48 ms
acd838e+dirty 3849.78 ms 1230.00 ms -2619.78 ms
fa21fca+dirty 3840.43 ms 1224.42 ms -2616.02 ms
0d9949d+dirty 1211.38 ms 1219.67 ms 8.29 ms
bc8f61e+dirty 3819.00 ms 1220.22 ms -2598.78 ms
ca9d079+dirty 3835.63 ms 1218.68 ms -2616.95 ms
5a316ea+dirty 3820.11 ms 1211.28 ms -2608.83 ms

App size

Revision Plain With Sentry Diff
2cac31b+dirty 4.98 MiB 6.55 MiB 1.58 MiB
244f6e8+dirty 4.98 MiB 6.56 MiB 1.58 MiB
61cc206+dirty 4.98 MiB 6.55 MiB 1.57 MiB
04207c4+dirty 3.38 MiB 4.76 MiB 1.38 MiB
acd838e+dirty 5.15 MiB 6.70 MiB 1.55 MiB
fa21fca+dirty 4.98 MiB 6.55 MiB 1.57 MiB
0d9949d+dirty 3.38 MiB 4.76 MiB 1.38 MiB
bc8f61e+dirty 4.98 MiB 6.47 MiB 1.49 MiB
ca9d079+dirty 5.15 MiB 6.69 MiB 1.53 MiB
5a316ea+dirty 4.98 MiB 6.51 MiB 1.53 MiB

@github-actions

Copy link
Copy Markdown
Contributor

iOS (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 3844.38 ms 1221.17 ms -2623.21 ms
Size 4.98 MiB 6.56 MiB 1.58 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
2cac31b+dirty 3854.43 ms 1212.35 ms -2642.08 ms
244f6e8+dirty 3825.51 ms 1217.76 ms -2607.75 ms
9474ead+dirty 3823.33 ms 1208.31 ms -2615.03 ms
44c8b3f+dirty 3849.24 ms 1209.94 ms -2639.31 ms
61cc206+dirty 3822.60 ms 1206.17 ms -2616.43 ms
acd838e+dirty 3835.94 ms 1215.87 ms -2620.07 ms
b0d3373+dirty 3842.49 ms 1218.49 ms -2624.00 ms
fa21fca+dirty 3845.12 ms 1215.89 ms -2629.24 ms
0d9949d+dirty 1203.94 ms 1202.27 ms -1.67 ms
a5d243c+dirty 3827.92 ms 1220.10 ms -2607.81 ms

App size

Revision Plain With Sentry Diff
2cac31b+dirty 4.98 MiB 6.55 MiB 1.58 MiB
244f6e8+dirty 4.98 MiB 6.56 MiB 1.58 MiB
9474ead+dirty 5.15 MiB 6.71 MiB 1.55 MiB
44c8b3f+dirty 5.15 MiB 6.66 MiB 1.51 MiB
61cc206+dirty 4.98 MiB 6.55 MiB 1.57 MiB
acd838e+dirty 5.15 MiB 6.70 MiB 1.55 MiB
b0d3373+dirty 5.15 MiB 6.68 MiB 1.53 MiB
fa21fca+dirty 4.98 MiB 6.55 MiB 1.57 MiB
0d9949d+dirty 3.38 MiB 4.76 MiB 1.38 MiB
a5d243c+dirty 5.15 MiB 6.68 MiB 1.53 MiB

@github-actions

Copy link
Copy Markdown
Contributor

Android (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 423.51 ms 487.04 ms 63.53 ms
Size 49.74 MiB 55.38 MiB 5.64 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
1d3572b+dirty 435.35 ms 487.32 ms 51.96 ms
d2eadf8+dirty 414.64 ms 454.56 ms 39.92 ms
7d8c8bd+dirty 417.45 ms 462.10 ms 44.65 ms
bf168a4+dirty 418.21 ms 489.74 ms 71.53 ms
890d145+dirty 504.54 ms 491.55 ms -12.99 ms
ad66da3+dirty 468.46 ms 533.56 ms 65.10 ms
15d4514+dirty 406.77 ms 428.06 ms 21.29 ms
a0a3177+dirty 441.27 ms 499.86 ms 58.59 ms
6acdf1d+dirty 513.58 ms 608.31 ms 94.72 ms
038a6d7+dirty 524.82 ms 531.92 ms 7.10 ms

App size

Revision Plain With Sentry Diff
1d3572b+dirty 49.74 MiB 55.38 MiB 5.63 MiB
d2eadf8+dirty 48.30 MiB 53.48 MiB 5.18 MiB
7d8c8bd+dirty 48.30 MiB 53.54 MiB 5.23 MiB
bf168a4+dirty 49.74 MiB 55.09 MiB 5.35 MiB
890d145+dirty 43.75 MiB 48.14 MiB 4.39 MiB
ad66da3+dirty 48.30 MiB 53.49 MiB 5.19 MiB
15d4514+dirty 48.30 MiB 53.60 MiB 5.30 MiB
a0a3177+dirty 49.74 MiB 55.37 MiB 5.63 MiB
6acdf1d+dirty 49.74 MiB 55.09 MiB 5.34 MiB
038a6d7+dirty 48.30 MiB 53.60 MiB 5.30 MiB

@github-actions

Copy link
Copy Markdown
Contributor

Android (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 425.08 ms 477.16 ms 52.08 ms
Size 49.74 MiB 55.38 MiB 5.64 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
1d3572b+dirty 444.48 ms 478.42 ms 33.94 ms
6177334+dirty 404.80 ms 456.74 ms 51.94 ms
5a23c47+dirty 406.83 ms 451.47 ms 44.64 ms
a3265b6+dirty 410.96 ms 444.76 ms 33.80 ms
bf168a4+dirty 430.60 ms 459.31 ms 28.71 ms
ca9d079+dirty 460.67 ms 512.54 ms 51.87 ms
ef27341+dirty 519.02 ms 553.42 ms 34.40 ms
23598c3+dirty 371.92 ms 420.65 ms 48.74 ms
7d6fd3a+dirty 435.06 ms 458.78 ms 23.72 ms
a50b33d+dirty 353.21 ms 398.48 ms 45.27 ms

App size

Revision Plain With Sentry Diff
1d3572b+dirty 49.74 MiB 55.38 MiB 5.63 MiB
6177334+dirty 48.30 MiB 53.54 MiB 5.23 MiB
5a23c47+dirty 49.74 MiB 54.82 MiB 5.07 MiB
a3265b6+dirty 48.30 MiB 53.58 MiB 5.28 MiB
bf168a4+dirty 49.74 MiB 55.09 MiB 5.35 MiB
ca9d079+dirty 48.30 MiB 53.58 MiB 5.28 MiB
ef27341+dirty 48.30 MiB 53.54 MiB 5.24 MiB
23598c3+dirty 43.94 MiB 49.02 MiB 5.08 MiB
7d6fd3a+dirty 43.94 MiB 49.00 MiB 5.06 MiB
a50b33d+dirty 43.94 MiB 48.94 MiB 5.00 MiB

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.

JS exceptions often lack debug_meta on Hermes; profiling path already has a robust Debug ID lookup

1 participant