Skip to content

Commit eab8797

Browse files
committed
fix(node): ignore error rethrows in local variables integration
1 parent 615c670 commit eab8797

File tree

1 file changed

+25
-2
lines changed
  • packages/node/src/integrations/local-variables

1 file changed

+25
-2
lines changed

packages/node/src/integrations/local-variables/worker.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import type { Debugger, InspectorNotification, Runtime } from 'node:inspector';
22
import { Session } from 'node:inspector/promises';
33
import { parentPort, workerData } from 'node:worker_threads';
4-
import type { StackParser } from '@sentry/types';
4+
import type { StackFrame, StackParser } from '@sentry/types';
55
import { createStackParser, nodeStackLineParser } from '@sentry/utils';
66
import { createGetModuleFromFilename } from '../../utils/module';
77
import type { LocalVariablesWorkerArgs, PausedExceptionEvent, RateLimitIncrement, Variables } from './common';
8-
import { createRateLimiter, hashFromStack } from './common';
8+
import { createRateLimiter, functionNamesMatch, hashFromStack } from './common';
99

1010
const options: LocalVariablesWorkerArgs = workerData;
1111

@@ -104,9 +104,24 @@ async function handlePaused(
104104
return;
105105
}
106106

107+
const originalErrorStackFrames: StackFrame[] = stackParser(
108+
data.description,
109+
).filter((frame) => frame.function !== 'new Promise');
110+
111+
// Debugger frames being longer than the originalErrorStackFrames means they definitely dont match
112+
// Debugger callFrames don't include anything beyond an async boundary, so they should be SHORTER or equal to the full error stack
113+
// If they are longer, we are in a re-throw and we should stop to avoid overriding the error's detected vars from the original throw
114+
if (callFrames.length > originalErrorStackFrames.length) {
115+
return;
116+
}
117+
107118
const frames = [];
108119

109120
for (let i = 0; i < callFrames.length; i++) {
121+
// sentry frames are in reverse order
122+
const originalErrorStackFramesIndex =
123+
originalErrorStackFrames.length - 1 - i;
124+
110125
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
111126
const { scopeChain, functionName, this: obj } = callFrames[i]!;
112127

@@ -115,6 +130,14 @@ async function handlePaused(
115130
// obj.className is undefined in ESM modules
116131
const fn = obj.className === 'global' || !obj.className ? functionName : `${obj.className}.${functionName}`;
117132

133+
if (
134+
!functionNamesMatch(fn, originalErrorStackFrames[originalErrorStackFramesIndex]?.function)
135+
) {
136+
// If at any point we encounter a function name that doesn't match the original error stack, we stop
137+
// this means we are in a re-throw and we don't want to override the error's detected vars from the original throw
138+
return;
139+
}
140+
118141
if (localScope?.object.objectId === undefined) {
119142
frames[i] = { function: fn };
120143
} else {

0 commit comments

Comments
 (0)