diff --git a/packages/node/test/stacktrace.test.ts b/packages/node/test/stacktrace.test.ts index 5b0f6fc52e25..edd62c81d8e5 100644 --- a/packages/node/test/stacktrace.test.ts +++ b/packages/node/test/stacktrace.test.ts @@ -354,6 +354,63 @@ describe('Stack parsing', () => { ]); }); + test('parses with async frames Windows', () => { + // https://github.com/getsentry/sentry-javascript/issues/4692#issuecomment-1063835795 + const err = new Error(); + err.stack = + 'Error: Client request error\n' + + ' at Object.httpRequestError (file:///C:/code/node_modules/@waroncancer/gaia/lib/error/error-factory.js:17:73)\n' + + ' at Object.run (file:///C:/code/node_modules/@waroncancer/gaia/lib/http-client/http-client.js:81:36)\n' + + ' at processTicksAndRejections (node:internal/process/task_queues:96:5)\n' + + ' at async Object.send (file:///C:/code/lib/post-created/send-post-created-notification-module.js:17:27)\n' + + ' at async each (file:///C:/code/lib/process-post-events-module.js:14:21)\n'; + + const frames = parseStackFrames(stackParser, err); + + expect(frames).toEqual([ + { + filename: 'C:/code/lib/process-post-events-module.js', + module: 'process-post-events-module', + function: 'each', + lineno: 14, + colno: 21, + in_app: true, + }, + { + filename: 'C:/code/lib/post-created/send-post-created-notification-module.js', + module: 'send-post-created-notification-module', + function: 'Object.send', + lineno: 17, + colno: 27, + in_app: true, + }, + { + filename: 'node:internal/process/task_queues', + module: 'task_queues', + function: 'processTicksAndRejections', + lineno: 96, + colno: 5, + in_app: false, + }, + { + filename: 'C:/code/node_modules/@waroncancer/gaia/lib/http-client/http-client.js', + module: '@waroncancer.gaia.lib.http-client:http-client', + function: 'Object.run', + lineno: 81, + colno: 36, + in_app: false, + }, + { + filename: 'C:/code/node_modules/@waroncancer/gaia/lib/error/error-factory.js', + module: '@waroncancer.gaia.lib.error:error-factory', + function: 'Object.httpRequestError', + lineno: 17, + colno: 73, + in_app: false, + }, + ]); + }); + test('parses with colons in paths', () => { const err = new Error(); err.stack = diff --git a/packages/utils/src/node-stack-trace.ts b/packages/utils/src/node-stack-trace.ts index 43db209a5fc5..3b486be9148c 100644 --- a/packages/utils/src/node-stack-trace.ts +++ b/packages/utils/src/node-stack-trace.ts @@ -35,7 +35,7 @@ export function filenameIsInApp(filename: string, isNative: boolean = false): bo // It's not internal if it's an absolute linux path !filename.startsWith('/') && // It's not internal if it's an absolute windows path - !filename.includes(':\\') && + !filename.match(/^[A-Z]:/) && // It's not internal if the path is starting with a dot !filename.startsWith('.') && // It's not internal if the frame has a protocol. In node, this is usually the case if the file got pre-processed with a bundler like webpack @@ -103,6 +103,11 @@ export function node(getModule?: GetModuleFn): StackLineParserFn { let filename = lineMatch[2] && lineMatch[2].startsWith('file://') ? lineMatch[2].slice(7) : lineMatch[2]; const isNative = lineMatch[5] === 'native'; + // If it's a Windows path, trim the leading slash so that `/C:/foo` becomes `C:/foo` + if (filename && filename.match(/\/[A-Z]:/)) { + filename = filename.slice(1); + } + if (!filename && lineMatch[5] && !isNative) { filename = lineMatch[5]; }