mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(mcp): suppress unhandled error on stderr pipe in stdio transport (#99803)
* fix(mcp): suppress unhandled error on stderr pipe in stdio transport When child.stderr is piped to stderrStream without an error handler, a stream-level error (EPIPE, I/O failure) crashes the process. Add a noop error handler before the pipe, consistent with the error handlers already present on stdin and stdout. Co-Authored-By: Claude <noreply@anthropic.com> * test(mcp): add regression test for stderr pipe error suppression Co-Authored-By: Claude <noreply@anthropic.com> * fix(mcp): report stderr stream errors * fix(mcp): report stderr stream errors --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
@@ -204,4 +204,23 @@ describe("OpenClawStdioClientTransport", () => {
|
||||
"write after end",
|
||||
);
|
||||
});
|
||||
|
||||
it("reports stderr pipe errors without an unhandled error crash", async () => {
|
||||
const child = new MockChildProcess();
|
||||
spawnMock.mockReturnValue(child);
|
||||
|
||||
const transport = new OpenClawStdioClientTransport({ command: "npx", stderr: "pipe" });
|
||||
const onerror = vi.fn();
|
||||
Object.assign(transport, { onerror });
|
||||
const started = transport.start();
|
||||
child.emit("spawn");
|
||||
await started;
|
||||
|
||||
const error = new Error("simulated pipe error");
|
||||
expect(() => child.stderr?.emit("error", error)).not.toThrow();
|
||||
expect(onerror).toHaveBeenCalledWith(error);
|
||||
|
||||
child.stderr.write("server diagnostic");
|
||||
expect(transport.stderr?.read()?.toString()).toBe("server diagnostic");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -86,6 +86,7 @@ export class OpenClawStdioClientTransport implements Transport {
|
||||
});
|
||||
child.stdout?.on("error", (error: Error) => this.onerror?.(error));
|
||||
if (this.stderrStream && child.stderr) {
|
||||
child.stderr.on("error", (error: Error) => this.onerror?.(error));
|
||||
child.stderr.pipe(this.stderrStream);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user