Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions packages/core/src/v3/errors.stacktrace.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { describe, it, expect } from "vitest";
import { correctErrorStackTrace } from "./errors.js";

const rawStackTrace = `
Error: Failed to fetch image: Bad Request
at fetchMediaContent (file:///src/modules/webhooks/utils.ts:83:11)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at getMediaContent (file:///src/modules/trigger/utils.ts:132:20)
at run (file:///src/modules/trigger/createDocumentFromWhapi.ts:67:32)
at _RunTimelineMetricsAPI.measureMetric (file:///.npm/_npx/trigger.dev/core/src/v3/runTimelineMetrics/index.ts:67:22)
at file:///.npm/_npx/trigger.dev/core/src/v3/workers/taskExecutor.ts:128:28
at ConsoleInterceptor.intercept (file:///.npm/_npx/trigger.dev/core/src/v3/consoleInterceptor.ts:36:14)
`;

describe("correctErrorStackTrace", () => {
it("filters internal stack frames and keeps user code", () => {
const cleaned = correctErrorStackTrace(rawStackTrace);
expect(cleaned).toBe(
[
"Error: Failed to fetch image: Bad Request",
" at fetchMediaContent (file:///src/modules/webhooks/utils.ts:83:11)",
" at getMediaContent (file:///src/modules/trigger/utils.ts:132:20)",
" at run (file:///src/modules/trigger/createDocumentFromWhapi.ts:67:32)",
].join("\n")
);
});
});
37 changes: 29 additions & 8 deletions packages/core/src/v3/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -351,23 +351,28 @@ export function correctErrorStackTrace(
projectDir?: string,
options?: { removeFirstLine?: boolean; isDev?: boolean }
) {
const [errorLine, ...traceLines] = stackTrace.split("\n");
const [errorLine, ...traceLines] = stackTrace.split("\n").map((l) => l.trimEnd());

return [
options?.removeFirstLine ? undefined : errorLine,
...traceLines.map((line) => correctStackTraceLine(line, projectDir, options?.isDev)),
]
const cleanedLines = traceLines
.map((line) => correctStackTraceLine(line, projectDir, options?.isDev))
.filter((l): l is string => Boolean(l))
// Avoid flooding Slack with deep stacks – keep the first few relevant lines
.slice(0, 5);

return [options?.removeFirstLine ? undefined : errorLine.trimEnd(), ...cleanedLines]
.filter(Boolean)
.join("\n");
}

// Stack trace lines that are internal to Trigger.dev or Node and should be removed
const LINES_TO_IGNORE = [
/ConsoleInterceptor/,
/TriggerTracer/,
/TaskExecutor/,
/EXECUTE_TASK_RUN/,
/@trigger.dev\/core/,
/packages\/core\/src\/v3/,
/@trigger.dev\/core/, // compiled package paths
/packages\/core\/src\/v3/, // local package paths
/\/\.npm\/_npx\/trigger\.dev\/core/, // npx execution paths
/safeJsonProcess/,
/__entryPoint.ts/,
/ZodIpc/,
Expand All @@ -380,7 +385,23 @@ function correctStackTraceLine(line: string, projectDir?: string, isDev?: boolea
return;
}

// Check to see if the path is inside the project directory
// Remove Node internal frames such as "node:internal/..." or "internal/..."
// We check for lines starting with these prefixes or wrapped in parentheses.
if (
line.includes("(node:") ||
line.trimStart().startsWith("node:") ||
line.includes("(internal/") ||
line.trimStart().startsWith("internal/")
) {
return;
}

// Ignore generic node_modules paths unless they are inside the provided project directory
if (/node_modules/.test(line) && (!projectDir || !line.includes(projectDir))) {
return;
}

// Check to see if the path is inside the project directory when running locally
if (isDev && projectDir && !line.includes(projectDir)) {
return;
}
Expand Down