From b2154fab80fec3028b7aa252680df514e3e49970 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Thu, 19 Feb 2026 10:59:08 +0100 Subject: [PATCH 1/5] fix(core): Wrap decodeURI in node stack trace parser to handle malformed URIs Fixes #19391 Co-authored-by: Cursor --- packages/core/src/utils/node-stack-trace.ts | 10 +++++++++- packages/core/test/lib/utils/stacktrace.test.ts | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/core/src/utils/node-stack-trace.ts b/packages/core/src/utils/node-stack-trace.ts index 1132471b0e8f..142e296da2fa 100644 --- a/packages/core/src/utils/node-stack-trace.ts +++ b/packages/core/src/utils/node-stack-trace.ts @@ -116,7 +116,7 @@ export function node(getModule?: GetModuleFn): StackLineParserFn { } return { - filename: filename ? decodeURI(filename) : undefined, + filename: filename ? _safeDecodeURI(filename) : undefined, module: getModule ? getModule(filename) : undefined, function: functionName, lineno: _parseIntOrUndefined(lineMatch[3]), @@ -148,3 +148,11 @@ export function nodeStackLineParser(getModule?: GetModuleFn): StackLineParser { function _parseIntOrUndefined(input: string | undefined): number | undefined { return parseInt(input || '', 10) || undefined; } + +function _safeDecodeURI(filename: string): string { + try { + return decodeURI(filename); + } catch { + return filename; + } +} diff --git a/packages/core/test/lib/utils/stacktrace.test.ts b/packages/core/test/lib/utils/stacktrace.test.ts index 0551a74be6f0..ffe5c70b8d75 100644 --- a/packages/core/test/lib/utils/stacktrace.test.ts +++ b/packages/core/test/lib/utils/stacktrace.test.ts @@ -392,4 +392,21 @@ describe('node', () => { expect(node(input)).toEqual(expectedOutput); }); + + it('returns the raw filename when decodeURI throws a URIError', () => { + const malformedFilename = '/path/to/%file%.js'; + const input = `at myFunction (${malformedFilename}:10:5)`; + + const result = node(input); + + expect(result?.filename).toBe(malformedFilename); + }); + + it('decodes a valid percent-encoded filename', () => { + const input = 'at myFunction (/path/to/my%20file.js:10:5)'; + + const result = node(input); + + expect(result?.filename).toBe('/path/to/my file.js'); + }); }); From 6eaef6f79d194300cf03cf96d206183c87c038ae Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Thu, 19 Feb 2026 11:13:02 +0100 Subject: [PATCH 2/5] fix passing undecoded filename to getModule --- packages/core/src/utils/node-stack-trace.ts | 9 +++++---- packages/core/test/lib/utils/stacktrace.test.ts | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/core/src/utils/node-stack-trace.ts b/packages/core/src/utils/node-stack-trace.ts index 142e296da2fa..8c05122e0b29 100644 --- a/packages/core/src/utils/node-stack-trace.ts +++ b/packages/core/src/utils/node-stack-trace.ts @@ -115,9 +115,10 @@ export function node(getModule?: GetModuleFn): StackLineParserFn { filename = lineMatch[5]; } + const maybeFilename = filename ? _safeDecodeURI(filename) : undefined; return { - filename: filename ? _safeDecodeURI(filename) : undefined, - module: getModule ? getModule(filename) : undefined, + filename: maybeFilename, + module: getModule?.(maybeFilename), function: functionName, lineno: _parseIntOrUndefined(lineMatch[3]), colno: _parseIntOrUndefined(lineMatch[4]), @@ -149,10 +150,10 @@ function _parseIntOrUndefined(input: string | undefined): number | undefined { return parseInt(input || '', 10) || undefined; } -function _safeDecodeURI(filename: string): string { +function _safeDecodeURI(filename: string): string | undefined { try { return decodeURI(filename); } catch { - return filename; + return undefined; } } diff --git a/packages/core/test/lib/utils/stacktrace.test.ts b/packages/core/test/lib/utils/stacktrace.test.ts index ffe5c70b8d75..e11c82c1c37d 100644 --- a/packages/core/test/lib/utils/stacktrace.test.ts +++ b/packages/core/test/lib/utils/stacktrace.test.ts @@ -393,13 +393,13 @@ describe('node', () => { expect(node(input)).toEqual(expectedOutput); }); - it('returns the raw filename when decodeURI throws a URIError', () => { + it('returns undefined when decodeURI throws a URIError', () => { const malformedFilename = '/path/to/%file%.js'; const input = `at myFunction (${malformedFilename}:10:5)`; const result = node(input); - expect(result?.filename).toBe(malformedFilename); + expect(result?.filename).toBeUndefined(); }); it('decodes a valid percent-encoded filename', () => { From 5e025434878a89596db9e83b30b7e678bafb4251 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Thu, 19 Feb 2026 11:18:09 +0100 Subject: [PATCH 3/5] adjust to return raw filename in filename but safeguard getModule --- packages/core/src/utils/node-stack-trace.ts | 6 +++--- packages/core/test/lib/utils/stacktrace.test.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/src/utils/node-stack-trace.ts b/packages/core/src/utils/node-stack-trace.ts index 8c05122e0b29..1dfe24e9f783 100644 --- a/packages/core/src/utils/node-stack-trace.ts +++ b/packages/core/src/utils/node-stack-trace.ts @@ -115,10 +115,10 @@ export function node(getModule?: GetModuleFn): StackLineParserFn { filename = lineMatch[5]; } - const maybeFilename = filename ? _safeDecodeURI(filename) : undefined; + const maybeDecodedFilename = filename ? _safeDecodeURI(filename) : undefined; return { - filename: maybeFilename, - module: getModule?.(maybeFilename), + filename: maybeDecodedFilename ?? filename, + module: maybeDecodedFilename && getModule?.(maybeDecodedFilename), function: functionName, lineno: _parseIntOrUndefined(lineMatch[3]), colno: _parseIntOrUndefined(lineMatch[4]), diff --git a/packages/core/test/lib/utils/stacktrace.test.ts b/packages/core/test/lib/utils/stacktrace.test.ts index e11c82c1c37d..2c35fd35ec48 100644 --- a/packages/core/test/lib/utils/stacktrace.test.ts +++ b/packages/core/test/lib/utils/stacktrace.test.ts @@ -393,7 +393,7 @@ describe('node', () => { expect(node(input)).toEqual(expectedOutput); }); - it('returns undefined when decodeURI throws a URIError', () => { + it('returns the raw filename when decodeURI throws a URIError', () => { const malformedFilename = '/path/to/%file%.js'; const input = `at myFunction (${malformedFilename}:10:5)`; From a7a753bf2d709b3006daf7ddb8eecea374be903c Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Thu, 19 Feb 2026 12:36:56 +0100 Subject: [PATCH 4/5] fix stacktrace test --- packages/core/test/lib/utils/stacktrace.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/test/lib/utils/stacktrace.test.ts b/packages/core/test/lib/utils/stacktrace.test.ts index 2c35fd35ec48..e0871c21835e 100644 --- a/packages/core/test/lib/utils/stacktrace.test.ts +++ b/packages/core/test/lib/utils/stacktrace.test.ts @@ -399,7 +399,7 @@ describe('node', () => { const result = node(input); - expect(result?.filename).toBeUndefined(); + expect(result?.filename).toBe(input); }); it('decodes a valid percent-encoded filename', () => { From 28dde86bc4dbe0ac44e2c76371584f071c054104 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Thu, 19 Feb 2026 15:57:42 +0100 Subject: [PATCH 5/5] fix test for real --- packages/core/test/lib/utils/stacktrace.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/test/lib/utils/stacktrace.test.ts b/packages/core/test/lib/utils/stacktrace.test.ts index e0871c21835e..49ea7fcc0ba5 100644 --- a/packages/core/test/lib/utils/stacktrace.test.ts +++ b/packages/core/test/lib/utils/stacktrace.test.ts @@ -399,7 +399,7 @@ describe('node', () => { const result = node(input); - expect(result?.filename).toBe(input); + expect(result?.filename).toBe('/path/to/%file%.js'); }); it('decodes a valid percent-encoded filename', () => {