Compare commits

...

1 Commits

Author SHA1 Message Date
Claude Bot
e7164128c6 fix(child_process): remove self-referencing cycle in execSync/execFileSync errors
In `checkExecSyncError`, `ObjectAssign(err, ret)` copies `ret.error`
onto `err`, but `err` IS `ret.error`, creating `err.error === err`.
This causes `JSON.stringify(err)` to throw with a cyclic structure error.

Delete the `.error` property after the assign to break the cycle.

Closes #26844

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-09 23:25:35 +00:00
2 changed files with 27 additions and 0 deletions

View File

@@ -1016,6 +1016,9 @@ function checkExecSyncError(ret, args, cmd?) {
if (ret.error) {
err = ret.error;
ObjectAssign(err, ret);
// ObjectAssign copies ret.error onto err, but err IS ret.error,
// creating a self-referencing cycle (err.error === err). Remove it.
delete err.error;
} else if (ret.status !== 0) {
let msg = "Command failed: ";
msg += cmd || ArrayPrototypeJoin.$call(args, " ");

View File

@@ -0,0 +1,24 @@
import { expect, test } from "bun:test";
import { execFileSync, execSync } from "child_process";
test("execFileSync error should not have self-referencing cycle", () => {
try {
execFileSync("nonexistent_binary_xyz_123");
expect.unreachable();
} catch (err: any) {
// err.error should not be the same object as err (self-referencing cycle)
expect(err.error).not.toBe(err);
// JSON.stringify should not throw due to cyclic structure
expect(() => JSON.stringify(err)).not.toThrow();
}
});
test("execSync error should not have self-referencing cycle", () => {
try {
execSync("nonexistent_binary_xyz_123");
expect.unreachable();
} catch (err: any) {
expect(err.error).not.toBe(err);
expect(() => JSON.stringify(err)).not.toThrow();
}
});