Skip to content

fix(android): Use componentStack as fallback for missing error stack traces#5965

Open
antonis wants to merge 5 commits intomainfrom
antonis/fix-missing-stacktrace-android-v2
Open

fix(android): Use componentStack as fallback for missing error stack traces#5965
antonis wants to merge 5 commits intomainfrom
antonis/fix-missing-stacktrace-android-v2

Conversation

@antonis
Copy link
Copy Markdown
Contributor

@antonis antonis commented Apr 7, 2026

📢 Type of change

  • Bugfix

📜 Description

When React render errors occur on Android with Hermes, the error may arrive at ErrorUtils.setGlobalHandler without a usable .stack property (empty or message-only). However, React's ReactFiberErrorDialog attaches a .componentStack to the error object before it reaches the handler. The componentStack contains component locations with bundle offsets that can be symbolicated by Sentry.

This PR uses componentStack as a fallback for error.stack when the stack has no frames, so that eventFromException can extract frames with source locations.

The fix handles both cases:

  • error.stack is undefined/empty
  • error.stack is a message-only string with no frame lines (e.g. "Error: Value is undefined, expected an Object")

Note: The componentStack is a React component tree (not a JS execution stack). After symbolication, it shows which component caused the error and its source location, but not the exact call chain within the component. This is the best information available on the JS side for this class of errors.

💡 Motivation and Context

Fixes #5071

A user reported a fatal error "Value is undefined, expected an Object" arriving in Sentry with no stacktrace, while Crashlytics captured the same error with a full component stack as a JavascriptException. The root cause is that some Hermes/JSI errors have no .stack property, but React attaches .componentStack which contains the same location information.

See also: https://x.com/TheAnirudh/status/1954761591515476463

💚 How did you test it?

  • Added test verifying componentStack is used as fallback when .stack is missing
  • Added test verifying componentStack is used when .stack is message-only (no frames)
  • Added test verifying existing .stack with frames is not overridden
  • All 1216 tests pass, 0 lint errors
  • Verified defaultStackParser correctly parses the componentStack format including address at prefixes

📝 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
  • No breaking changes

🔮 Next steps

  • Verify with a real Android/Hermes app that the recovered component stack frames are correctly symbolicated

…traces

When React render errors occur on Android with Hermes, the error may
arrive at ErrorUtils.setGlobalHandler without a .stack property.
However, React attaches a .componentStack with component locations
and bundle offsets before the error reaches the handler.

Use componentStack as a fallback for error.stack so that
eventFromException can extract frames with source locations.

Fixes #5071

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 7, 2026

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(android): Use componentStack as fallback for missing error stack traces by antonis in #5965
  • fix(ios): Add SENTRY_PROJECT_ROOT env var for monorepo support by antonis in #5961
  • feat(ios): Add attachAllThreads option by antonis in #5960
  • fix(core): Lazy-load Metro internal modules to prevent Expo 55 import errors by lucas-zimerman in #5958
  • chore(deps): update Cocoa SDK to v9.9.0 by github-actions in #5956
  • chore(deps): update Maestro to v2.4.0 by github-actions in #5955
  • Feat: Fallback to stacktrace parsing by lucas-zimerman in #5946
  • fix(ci): Bump Node to 22 in size-analysis and testflight workflows by antonis in #5954
  • feat(playground): Open Sentry in desktop browser from Expo apps by antonis in #5947
  • chore(core): Bump sample app to React Native 0.84.1 by antonis in #5941
  • Size analysis for React Native SDK by alwx in #5949
  • chore(deps): bump lodash from 4.17.23 to 4.18.1 by dependabot in #5953
  • chore(deps): bump yauzl to ^3.2.1 by antonis in #5950
  • chore(deps): bump brace-expansion to ^2.0.3 by antonis in #5951
  • chore(deps): bump @xmldom/xmldom to fix XML injection by antonis in #5952

🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 7, 2026

Fails
🚫 Pull request is not ready for merge, please add the "ready-to-merge" label to the pull request

Generated by 🚫 dangerJS against 8c77549

@antonis
Copy link
Copy Markdown
Contributor Author

antonis commented Apr 7, 2026

@sentry review

@antonis
Copy link
Copy Markdown
Contributor Author

antonis commented Apr 7, 2026

@cursor review

@sentry
Copy link
Copy Markdown

sentry bot commented Apr 7, 2026

Sentry Build Distribution

App Name App ID Version Configuration Install Page
Sentry RN io.sentry.reactnative.sample 8.7.0 (82) Release Install Build

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor bot left a comment

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 bc7535c. Configure here.

antonis and others added 2 commits April 7, 2026 15:35
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@antonis antonis marked this pull request as ready for review April 7, 2026 14:26
// oxlint-disable-next-line typescript-eslint(no-unsafe-member-access)
if (error?.componentStack && (!error.stack || !hasStackFrames(error.stack))) {
// oxlint-disable-next-line typescript-eslint(no-unsafe-member-access)
error.stack = `${error.message || 'Error'}${error.componentStack}`;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

shouldn't we add an extra space between the parameters, so Error is not clued to the componentStack message?

Copy link
Copy Markdown
Collaborator

@lucas-zimerman lucas-zimerman left a comment

Choose a reason for hiding this comment

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

nit comment, other than that, LGTM!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing stacktrace in Value is undefined, expected an Object Error

2 participants