Skip to content

Commit 2c538d4

Browse files
committed
filter out internal frame from stack trace
1 parent 0ca0bfe commit 2c538d4

File tree

4 files changed

+58
-35
lines changed

4 files changed

+58
-35
lines changed

packages/miniflare/src/plugins/core/errors/index.ts

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import path from "path";
33
import { fileURLToPath } from "url";
44
import { z } from "zod";
55
import { Request, Response } from "../../../http";
6-
import { Log } from "../../../shared";
6+
import { Log, processStackTrace } from "../../../shared";
77
import { maybeParseURL } from "../../shared";
88
import {
99
contentsToString,
@@ -235,7 +235,14 @@ export function reviveError(
235235
error.stack = jsonError.stack;
236236

237237
// Try to apply source-mapping to the stack trace
238-
error.stack = getSourceMappedStack(workerSrcOpts, error);
238+
error.stack = processStackTrace(
239+
getSourceMappedStack(workerSrcOpts, error),
240+
(line, location) =>
241+
!location.includes(".wrangler/tmp") &&
242+
!location.includes("wrangler/templates/middleware")
243+
? line
244+
: null
245+
);
239246

240247
return error;
241248
}
@@ -278,19 +285,6 @@ export async function handlePrettyErrorRequest(
278285
const youch = new Youch();
279286

280287
youch.useTransformer((error) => {
281-
error.frames = error.frames
282-
.filter(
283-
(frame) =>
284-
!frame.fileName?.includes(".wrangler/tmp") &&
285-
!frame.fileName?.includes("wrangler/templates/middleware")
286-
)
287-
.map((frame) => {
288-
// To avoid Youch throwing an error if the frame has no fileName
289-
// This happens in tests which hides some parts of the stack trace
290-
frame.fileName ??= "";
291-
292-
return frame;
293-
});
294288
error.hint = [
295289
'<a href="https://developers.cloudflare.com/workers/" target="_blank" style="text-decoration:none;font-style:normal;padding:5px">📚 Workers Docs</a>',
296290
'<a href="https://discord.cloudflare.com" target="_blank" style="text-decoration:none;font-style: normal;padding:5px">💬 Workers Discord</a>',

packages/miniflare/src/plugins/core/modules.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ const builtinModulesWithPrefix = builtinModules.concat(
3030

3131
// Module identifier used if script came from `script` option
3232
export function buildStringScriptPath(workerIndex: number) {
33-
return `script:${workerIndex}`;
33+
return `script-${workerIndex}`;
3434
}
35-
const stringScriptRegexp = /^script:(\d+)$/;
35+
const stringScriptRegexp = /^script-(\d+)$/;
3636
export function maybeGetStringScriptPathIndex(
3737
scriptPath: string
3838
): number | undefined {

packages/miniflare/src/shared/log.ts

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,40 @@ export function prefixError(prefix: string, e: any): Error {
3535
return e;
3636
}
3737

38-
function dimInternalStackLine(line: string): string {
39-
if (
40-
line.startsWith(" at") &&
41-
(!line.includes(cwd) || line.includes(cwdNodeModules))
42-
) {
43-
return dim(line);
38+
// Regex matches V8 stack frame lines with and without function name:
39+
// at fnName (file:line:col)
40+
// at file:line:col
41+
const frameRegex = /^\s*at(?:\s+[^\s()]+)?\s*\(?(.+?)\)?$/;
42+
/**
43+
* Processes a stack trace by applying a custom frame transformer.
44+
* The transformer receives each frame line and its location (file:line:column);
45+
* if it returns null, that frame is dropped; otherwise its return value replaces the line.
46+
*/
47+
export function processStackTrace(
48+
stack: string,
49+
transformFrame: (line: string, location: string) => string | null
50+
): string {
51+
const lines = stack.split("\n");
52+
const result: string[] = [];
53+
54+
for (const line of lines) {
55+
const match = frameRegex.exec(line);
56+
57+
if (match) {
58+
const location = match[1];
59+
const transformed = transformFrame(line, location);
60+
if (transformed !== null) {
61+
result.push(transformed);
62+
}
63+
64+
continue; // if transformed is null, drop the frame
65+
}
66+
67+
// Non-frame lines (e.g., error message) are preserved
68+
result.push(line);
4469
}
45-
return line;
70+
71+
return result.join("\n");
4672
}
4773

4874
/**
@@ -60,11 +86,14 @@ export function formatError(error: Error): string {
6086
let message: string;
6187

6288
if (error.stack) {
63-
message = error.stack
64-
.split("\n")
65-
// Dim internal stack trace lines to highlight user code
66-
.map(dimInternalStackLine)
67-
.join("\n");
89+
message = processStackTrace(error.stack, (line) => {
90+
if (!line.includes(cwd) || line.includes(cwdNodeModules)) {
91+
// Dim internal stack trace lines to highlight user code
92+
return dim(line);
93+
}
94+
95+
return line;
96+
});
6897
} else {
6998
message = error.toString();
7099
}

packages/miniflare/test/plugins/core/errors/index.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ test("responds with pretty error page", async (t) => {
352352
t.regex(res.headers.get("Content-Type") ?? "", /^text\/html/);
353353
const text = await res.text();
354354
// ...including error, request method, URL and headers
355-
t.regex(text, /Test error!/);
355+
t.regex(text, /Unusual oops!/);
356356
t.regex(text, /Method.+POST/is);
357357
t.regex(text, /URL.+some-unusual-path/is);
358358
t.regex(text, /X-Unusual-Key.+some-unusual-value/is);
@@ -361,12 +361,12 @@ test("responds with pretty error page", async (t) => {
361361
const errorLogs = log.getLogs(LogLevel.ERROR);
362362
t.deepEqual(errorLogs, [
363363
`Error: Unusual oops!
364-
at doSomething (script)
365-
at Object.fetch (script)
364+
at doSomething (script-0:6:12)
365+
at Object.fetch (script-0:30:6)
366366
Caused by: Error: Test error
367-
at oops (script)
368-
at doSomething (script)
369-
at Object.fetch (script)`,
367+
at oops (script-0:13:11)
368+
at doSomething (script-0:4:5)
369+
at Object.fetch (script-0:30:6)`,
370370
]);
371371

372372
// Check `fetch()` accepting HTML returns pretty-error page

0 commit comments

Comments
 (0)