-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
fix(browser): Fix internal frame detection in minified bundles #20802
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ import type { Event } from '../types-hoist/event'; | |
| import type { StackFrame } from '../types-hoist/stackframe'; | ||
| import { forEachEnvelopeItem } from '../utils/envelope'; | ||
| import { getFramesFromEvent } from '../utils/stacktrace'; | ||
| import { GLOBAL_OBJ } from '../utils/worldwide'; | ||
|
|
||
| interface Options { | ||
| /** | ||
|
|
@@ -74,8 +75,27 @@ export const thirdPartyErrorFilterIntegration = defineIntegration((options: Opti | |
| }); | ||
| }, | ||
|
|
||
| preprocessEvent(event) { | ||
| // Snapshot the depth counter onto the event before any event processors run. | ||
| // This is necessary because async event processors could cause the finally block | ||
| // in sentryWrapped to decrement the counter before processEvent reads it. | ||
| if (options.ignoreSentryInternalFrames && (GLOBAL_OBJ._sentryWrappedDepth ?? 0) > 0) { | ||
| event.sdkProcessingMetadata = { | ||
| ...event.sdkProcessingMetadata, | ||
| insideSentryWrapped: true, | ||
| }; | ||
| } | ||
| }, | ||
|
|
||
| processEvent(event) { | ||
| const frameKeys = getBundleKeysForAllFramesWithFilenames(event, options.ignoreSentryInternalFrames); | ||
| const insideSentryWrapped = options.ignoreSentryInternalFrames | ||
| ? event.sdkProcessingMetadata?.insideSentryWrapped === true | ||
| : false; | ||
| const frameKeys = getBundleKeysForAllFramesWithFilenames( | ||
| event, | ||
| options.ignoreSentryInternalFrames, | ||
| insideSentryWrapped, | ||
| ); | ||
|
|
||
| if (frameKeys) { | ||
| const arrayMethod = | ||
|
|
@@ -106,20 +126,30 @@ export const thirdPartyErrorFilterIntegration = defineIntegration((options: Opti | |
| }; | ||
| }); | ||
|
|
||
| /** | ||
| * Checks if a stack frame is a Sentry internal frame by strictly matching: | ||
| * 1. The frame must be the last frame in the stack | ||
| * 2. The filename must indicate the internal helpers file | ||
| * 3. The context_line must contain the exact pattern "fn.apply(this, wrappedArguments)" | ||
| * 4. The comment pattern "Attempt to invoke user-land function" must be present in pre_context | ||
| * | ||
| */ | ||
| function isSentryInternalFrame(frame: StackFrame, frameIndex: number): boolean { | ||
| /** Checks if a frame is Sentry-internal via runtime depth, function name, or source patterns. */ | ||
| function isSentryInternalFrame(frame: StackFrame, frameIndex: number, insideSentryWrapped: boolean): boolean { | ||
| // Only match the last frame (index 0 in reversed stack) | ||
| if (frameIndex !== 0 || !frame.context_line || !frame.filename) { | ||
| if (frameIndex !== 0) { | ||
| return false; | ||
| } | ||
|
|
||
| // When processEvent runs inside a sentryWrapped call, the outermost frame is always | ||
| // the sentryWrapped function. This works regardless of minification/bundling because | ||
| // it's a runtime check, not a source pattern match. | ||
| if (insideSentryWrapped) { | ||
| return true; | ||
| } | ||
|
Comment on lines
+136
to
+141
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: In non-minified builds, Suggested FixRemove the unconditional check in Prompt for AI AgentThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chained errors cause wrong frame filtered as internalMedium Severity When Reviewed by Cursor Bugbot for commit 1ae6a53. Configure here.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this might be a legit issue, maybe we can narrow it down with something like: const maybeInsideSentryWrapped = insideSentryWrapped && event.exception?.values?.length === 1;and then gate it further to only the minified-shaped case: function isLikelyMinifiedSentryWrappedFrame(frame: StackFrame): boolean {
return !frame.context_line && !frame.pre_context && !!frame.function && frame.function.length <= 2;
}WDYT? |
||
|
|
||
| // Match by function name (works when function names survive bundling but source patterns don't) | ||
| if (frame.function === 'sentryWrapped') { | ||
| return true; | ||
| } | ||
|
|
||
| if (!frame.context_line || !frame.filename) { | ||
| return false; | ||
| } | ||
|
|
||
| // Match by source code patterns (works in development / unbundled builds) | ||
| if ( | ||
| !frame.filename.includes('sentry') || | ||
| !frame.filename.includes('helpers') || // Filename would look something like this: 'node_modules/@sentry/browser/build/npm/esm/helpers.js' | ||
|
|
@@ -144,6 +174,7 @@ function isSentryInternalFrame(frame: StackFrame, frameIndex: number): boolean { | |
| function getBundleKeysForAllFramesWithFilenames( | ||
| event: Event, | ||
| ignoreSentryInternalFrames?: boolean, | ||
| insideSentryWrapped?: boolean, | ||
| ): string[][] | undefined { | ||
| const frames = getFramesFromEvent(event); | ||
|
|
||
|
|
@@ -163,7 +194,7 @@ function getBundleKeysForAllFramesWithFilenames( | |
| return false; | ||
| } | ||
| // Optionally ignore Sentry internal frames | ||
| return !ignoreSentryInternalFrames || !isSentryInternalFrame(frame, index); | ||
| return !ignoreSentryInternalFrames || !isSentryInternalFrame(frame, index, !!insideSentryWrapped); | ||
| }) | ||
| .map(frame => { | ||
| if (!frame.module_metadata) { | ||
|
|
||


Uh oh!
There was an error while loading. Please reload this page.