Compare commits

...

2 Commits

Author SHA1 Message Date
Franck Nijhof 45b43de020 Prevent error logger from crashing on unparseable stack traces
When createLogMessage received an error whose stack stacktrace-js could
not parse (for example a DOMException such as "AbortError: Transition was
skipped"), fromError threw "Cannot parse given Error object". That throw
escaped createLogMessage, so the global unhandledrejection handler logged
"Failure writing unhandled promise rejection to system log" and the
original error was never recorded.

Wrap the stacktrace extraction in a try/catch and fall back to the raw
error stack (or the provided stack fallback) so the logger stays robust
and still records the original error.
2026-06-12 20:28:35 +00:00
renovate[bot] 273967fe70 Update dependency prettier to v3.8.4 (#52569)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-12 19:20:28 +03:00
4 changed files with 75 additions and 16 deletions
+1 -1
View File
@@ -186,7 +186,7 @@
"lodash.template": "4.18.1",
"map-stream": "0.0.7",
"pinst": "3.0.0",
"prettier": "3.8.3",
"prettier": "3.8.4",
"rspack-manifest-plugin": "5.2.2",
"serve": "14.2.6",
"sinon": "22.0.0",
+18 -10
View File
@@ -60,16 +60,24 @@ export const createLogMessage = async (
// - a possible list of aggregated errors
if (error instanceof Error) {
lines.push(error.toString() || messageFallback);
const stackLines = (await fromError(error))
.slice(0, MAX_STACK_FRAMES)
.map((frame) => {
frame.fileName ??= "";
if (URL.canParse(frame.fileName)) {
frame.fileName = new URL(frame.fileName).pathname;
}
frame.fileName = frame.fileName.replace(REMOVAL_PATHS, "");
return frame.toString();
});
let stackLines: (string | undefined)[];
try {
stackLines = (await fromError(error))
.slice(0, MAX_STACK_FRAMES)
.map((frame) => {
frame.fileName ??= "";
if (URL.canParse(frame.fileName)) {
frame.fileName = new URL(frame.fileName).pathname;
}
frame.fileName = frame.fileName.replace(REMOVAL_PATHS, "");
return frame.toString();
});
} catch {
// stacktrace-js cannot always parse a stack (for example a DOMException
// with no, or an unrecognized, stack), so fall back to the raw stack
// instead of letting the error logger itself throw.
stackLines = error.stack ? [error.stack] : [];
}
lines.push(...(stackLines.length > 0 ? stackLines : [stackFallback]));
// @ts-expect-error Requires library bump to ES2022
if (error.cause) {
+51
View File
@@ -0,0 +1,51 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { createLogMessage } from "../../src/resources/log-message";
const fromError = vi.hoisted(() => vi.fn());
vi.mock("stacktrace-js", () => ({ fromError }));
describe("createLogMessage", () => {
beforeEach(() => {
fromError.mockReset();
});
it("includes the error message and parsed stack frames", async () => {
fromError.mockResolvedValue([
{ fileName: "https://example.com/foo.js", toString: () => "at foo.js" },
]);
const error = new Error("boom");
const message = await createLogMessage(error);
expect(message).toContain("Error: boom");
expect(message).toContain("at foo.js");
});
it("does not throw when stacktrace-js cannot parse the stack", async () => {
fromError.mockRejectedValue(new Error("Cannot parse given Error object"));
const error = new Error("boom");
error.stack = "Error: boom\n at <anonymous>";
const message = await createLogMessage(error);
expect(message).toContain("Error: boom");
// Falls back to the raw stack instead of crashing the logger.
expect(message).toContain("at <anonymous>");
});
it("falls back to the provided stack fallback when no stack is available", async () => {
fromError.mockRejectedValue(new Error("Cannot parse given Error object"));
const error = new Error("boom");
error.stack = undefined;
const message = await createLogMessage(
error,
undefined,
undefined,
"@unknown:0:0"
);
expect(message).toContain("@unknown:0:0");
});
});
+5 -5
View File
@@ -8570,7 +8570,7 @@ __metadata:
node-vibrant: "npm:4.0.4"
object-hash: "npm:3.0.0"
pinst: "npm:3.0.0"
prettier: "npm:3.8.3"
prettier: "npm:3.8.4"
punycode: "npm:2.3.1"
qr-scanner: "npm:1.4.2"
qrcode: "npm:1.5.4"
@@ -11350,12 +11350,12 @@ __metadata:
languageName: node
linkType: hard
"prettier@npm:3.8.3":
version: 3.8.3
resolution: "prettier@npm:3.8.3"
"prettier@npm:3.8.4":
version: 3.8.4
resolution: "prettier@npm:3.8.4"
bin:
prettier: bin/prettier.cjs
checksum: 10/4b3b12cbb29e4c96bed936e5d070167552500c18d37676fb3e0caae6199c42860662608e4dc116230698f6e2bb0267ef2548158224c92d40f188d309d72fdd6f
checksum: 10/54684a3cc6689238692b29fab541c01934af7677be94c02293ba49981a1ac121c8bebe2a865f0c3b963e99d208f847c53aed354cc0ce8750e2d45791d64506c5
languageName: node
linkType: hard