Skip to content

Commit

Permalink
fix(node): Local variables skipped after Promise (#11234)
Browse files Browse the repository at this point in the history
The debugger call stack does not include the `new Promise` frames that
are parsed from `error.stack`. This means that when we go through the
frames to apply the local variables, the frames don't match up and we
bail.

This patch ignores those frames when matching functions in the frames.
  • Loading branch information
timfish authored Mar 22, 2024
1 parent 7c2f2b4 commit 28db511
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ Sentry.init({
});

class Some {
two(name) {
throw new Error('Enough!');
async two(name) {
return new Promise((_, reject) => {
reject(new Error('Enough!'));
});
}
}

function one(name) {
async function one(name) {
const arr = [1, '2', null];
const obj = {
name,
Expand All @@ -30,12 +32,12 @@ function one(name) {

const ty = new Some();

ty.two(name);
await ty.two(name);
}

setTimeout(() => {
setTimeout(async () => {
try {
one('some name');
await one('some name');
} catch (e) {
Sentry.captureException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,29 +288,31 @@ const _localVariablesSyncIntegration = ((
return;
}

const frameCount = exception.stacktrace?.frames?.length || 0;
// Filter out frames where the function name is `new Promise` since these are in the error.stack frames
// but do not appear in the debugger call frames
const frames = (exception.stacktrace?.frames || []).filter(frame => frame.function !== 'new Promise');

for (let i = 0; i < frameCount; i++) {
for (let i = 0; i < frames.length; i++) {
// Sentry frames are in reverse order
const frameIndex = frameCount - i - 1;
const frameIndex = frames.length - i - 1;

// Drop out if we run out of frames to match up
if (!exception?.stacktrace?.frames?.[frameIndex] || !cachedFrame[i]) {
if (!frames[frameIndex] || !cachedFrame[i]) {
break;
}

if (
// We need to have vars to add
cachedFrame[i].vars === undefined ||
// We're not interested in frames that are not in_app because the vars are not relevant
exception.stacktrace.frames[frameIndex].in_app === false ||
frames[frameIndex].in_app === false ||
// The function names need to match
!functionNamesMatch(exception.stacktrace.frames[frameIndex].function, cachedFrame[i].function)
!functionNamesMatch(frames[frameIndex].function, cachedFrame[i].function)
) {
continue;
}

exception.stacktrace.frames[frameIndex].vars = cachedFrame[i].vars;
frames[frameIndex].vars = cachedFrame[i].vars;
}
}

Expand Down

0 comments on commit 28db511

Please sign in to comment.