From f777e2819e732f27e22d75ede218fa527815bfa5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 22 Jun 2026 01:40:21 +0000 Subject: [PATCH 1/5] Initial plan From f3cdff6fad4f216e74b12454b68d7e57894a7c4f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 22 Jun 2026 01:51:16 +0000 Subject: [PATCH 2/5] Initial: investigating submit_pull_request_review [object Object] error Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/agentics-maintenance.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/agentics-maintenance.yml b/.github/workflows/agentics-maintenance.yml index 2c1975dfab9..608a43249f0 100644 --- a/.github/workflows/agentics-maintenance.yml +++ b/.github/workflows/agentics-maintenance.yml @@ -23,13 +23,13 @@ # # This file defines the generated agentic maintenance workflow for this repository. # It runs scheduled cleanup for expiring safe outputs and supports manual maintenance operations. -# +# # This workflow is generated automatically when workflows use expiring safe outputs # or when repository maintenance features are enabled in .github/workflows/aw.json. -# +# # To disable maintenance workflow generation, set in .github/workflows/aw.json: # {"maintenance": false} -# +# # Agentic maintenance docs: # https://github.github.com/gh-aw/reference/ephemerals/#manual-maintenance-operations # From 2c921d57272d885031f524235bf1dd3e986f55dd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 22 Jun 2026 01:56:11 +0000 Subject: [PATCH 3/5] fix: propagate error code and message from thrown plain objects in handleMessage The catch block in handleMessage used `String(e)` for non-Error thrown values, producing `[object Object]` instead of the actual validation message. This caused submit_pull_request_review calls to fail with -32603 `[object Object]` instead of the descriptive -32602 validation error when safe_outputs_handlers.cjs threw plain objects like { code: -32602, message: '...' }. Align handleMessage with the existing handleRequest pattern: extract the error code from the thrown value (requiring it to be negative per JSON-RPC spec) and use e.message when available. Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/mcp_server_core.cjs | 6 ++- actions/setup/js/mcp_server_core.test.cjs | 49 +++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/actions/setup/js/mcp_server_core.cjs b/actions/setup/js/mcp_server_core.cjs index 7b707a21c4e..778a3affe93 100644 --- a/actions/setup/js/mcp_server_core.cjs +++ b/actions/setup/js/mcp_server_core.cjs @@ -984,7 +984,11 @@ async function handleMessage(server, req, defaultHandler) { server.replyError(id, -32601, `Method not found: ${method}`); } } catch (e) { - server.replyError(id, -32603, e instanceof Error ? e.message : String(e)); + // Use the error code only if it's a valid JSON-RPC error code (must be a negative integer). + // Subprocess exit codes (positive integers like 1, 2, etc.) must not be used as JSON-RPC + // error codes, as that would produce non-conformant responses (e.g. "code=1"). + const code = e && typeof e.code === "number" && e.code < 0 ? e.code : -32603; + server.replyError(id, code, e && e.message ? String(e.message) : String(e)); } } diff --git a/actions/setup/js/mcp_server_core.test.cjs b/actions/setup/js/mcp_server_core.test.cjs index e5819d785fc..7dddcb9f2b2 100644 --- a/actions/setup/js/mcp_server_core.test.cjs +++ b/actions/setup/js/mcp_server_core.test.cjs @@ -471,6 +471,55 @@ describe("mcp_server_core.cjs", () => { expect(results).toHaveLength(1); expect(results[0].result.content[0].text).toBe("default handler for no_handler_tool"); }); + + it("should return the code and message from a thrown plain object (not Error instance)", async () => { + const { registerTool, handleMessage } = await import("./mcp_server_core.cjs"); + + registerTool(server, { + name: "plain_throw_tool", + description: "A tool that throws a plain object", + inputSchema: { type: "object", properties: { input: { type: "string" } }, required: ["input"] }, + handler: () => { + throw { code: -32602, message: "ERR_VALIDATION: body required" }; + }, + }); + + await handleMessage(server, { + jsonrpc: "2.0", + id: 99, + method: "tools/call", + params: { name: "plain_throw_tool", arguments: { input: "x" } }, + }); + + expect(results).toHaveLength(1); + expect(results[0].error.code).toBe(-32602); + expect(results[0].error.message).toBe("ERR_VALIDATION: body required"); + expect(results[0].error.message).not.toContain("[object Object]"); + }); + + it("should fall back to -32603 when thrown plain object has no valid error code", async () => { + const { registerTool, handleMessage } = await import("./mcp_server_core.cjs"); + + registerTool(server, { + name: "no_code_throw_tool", + description: "A tool that throws a plain object without a code", + inputSchema: { type: "object", properties: { input: { type: "string" } }, required: ["input"] }, + handler: () => { + throw { message: "something went wrong" }; + }, + }); + + await handleMessage(server, { + jsonrpc: "2.0", + id: 100, + method: "tools/call", + params: { name: "no_code_throw_tool", arguments: { input: "x" } }, + }); + + expect(results).toHaveLength(1); + expect(results[0].error.code).toBe(-32603); + expect(results[0].error.message).toBe("something went wrong"); + }); }); describe("handleRequest", () => { From 2bd26fc7300ffa017e188398bca7e157e063edc8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 22 Jun 2026 02:42:31 +0000 Subject: [PATCH 4/5] fix: tighten JSON-RPC error code/message fallback in handleMessage Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/mcp_server_core.cjs | 4 +- actions/setup/js/mcp_server_core.test.cjs | 72 +++++++++++++++++++++++ 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/actions/setup/js/mcp_server_core.cjs b/actions/setup/js/mcp_server_core.cjs index 778a3affe93..0d0078c9118 100644 --- a/actions/setup/js/mcp_server_core.cjs +++ b/actions/setup/js/mcp_server_core.cjs @@ -987,8 +987,8 @@ async function handleMessage(server, req, defaultHandler) { // Use the error code only if it's a valid JSON-RPC error code (must be a negative integer). // Subprocess exit codes (positive integers like 1, 2, etc.) must not be used as JSON-RPC // error codes, as that would produce non-conformant responses (e.g. "code=1"). - const code = e && typeof e.code === "number" && e.code < 0 ? e.code : -32603; - server.replyError(id, code, e && e.message ? String(e.message) : String(e)); + const code = e && Number.isInteger(e.code) && e.code < 0 ? e.code : -32603; + server.replyError(id, code, e && e.message ? String(e.message) : "Internal error"); } } diff --git a/actions/setup/js/mcp_server_core.test.cjs b/actions/setup/js/mcp_server_core.test.cjs index 7dddcb9f2b2..41153ebd6dc 100644 --- a/actions/setup/js/mcp_server_core.test.cjs +++ b/actions/setup/js/mcp_server_core.test.cjs @@ -520,6 +520,78 @@ describe("mcp_server_core.cjs", () => { expect(results[0].error.code).toBe(-32603); expect(results[0].error.message).toBe("something went wrong"); }); + + it("should fall back to -32603 when thrown plain object has a positive code", async () => { + const { registerTool, handleMessage } = await import("./mcp_server_core.cjs"); + + registerTool(server, { + name: "positive_code_throw_tool", + description: "A tool that throws a plain object with a positive code", + inputSchema: { type: "object", properties: { input: { type: "string" } }, required: ["input"] }, + handler: () => { + throw { code: 1, message: "process exited with code 1" }; + }, + }); + + await handleMessage(server, { + jsonrpc: "2.0", + id: 101, + method: "tools/call", + params: { name: "positive_code_throw_tool", arguments: { input: "x" } }, + }); + + expect(results).toHaveLength(1); + expect(results[0].error.code).toBe(-32603); + expect(results[0].error.message).toBe("process exited with code 1"); + }); + + it("should fall back to -32603 and Internal error for thrown plain object without message", async () => { + const { registerTool, handleMessage } = await import("./mcp_server_core.cjs"); + + registerTool(server, { + name: "no_message_throw_tool", + description: "A tool that throws a plain object without a message", + inputSchema: { type: "object", properties: { input: { type: "string" } }, required: ["input"] }, + handler: () => { + throw { code: -32602 }; + }, + }); + + await handleMessage(server, { + jsonrpc: "2.0", + id: 102, + method: "tools/call", + params: { name: "no_message_throw_tool", arguments: { input: "x" } }, + }); + + expect(results).toHaveLength(1); + expect(results[0].error.code).toBe(-32602); + expect(results[0].error.message).toBe("Internal error"); + }); + + it("should fall back to -32603 when thrown plain object has a non-integer negative code", async () => { + const { registerTool, handleMessage } = await import("./mcp_server_core.cjs"); + + registerTool(server, { + name: "non_integer_code_throw_tool", + description: "A tool that throws a plain object with a non-integer code", + inputSchema: { type: "object", properties: { input: { type: "string" } }, required: ["input"] }, + handler: () => { + throw { code: -1.5, message: "fractional code should be ignored" }; + }, + }); + + await handleMessage(server, { + jsonrpc: "2.0", + id: 103, + method: "tools/call", + params: { name: "non_integer_code_throw_tool", arguments: { input: "x" } }, + }); + + expect(results).toHaveLength(1); + expect(results[0].error.code).toBe(-32603); + expect(results[0].error.message).toBe("fractional code should be ignored"); + }); }); describe("handleRequest", () => { From 60cc5c583490638f9bfc84bce8121017cd4244f9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 22 Jun 2026 02:46:18 +0000 Subject: [PATCH 5/5] test: clarify missing-message case and harden thrown error object guard Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/mcp_server_core.cjs | 2 +- actions/setup/js/mcp_server_core.test.cjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/actions/setup/js/mcp_server_core.cjs b/actions/setup/js/mcp_server_core.cjs index 0d0078c9118..35cd0c84905 100644 --- a/actions/setup/js/mcp_server_core.cjs +++ b/actions/setup/js/mcp_server_core.cjs @@ -987,7 +987,7 @@ async function handleMessage(server, req, defaultHandler) { // Use the error code only if it's a valid JSON-RPC error code (must be a negative integer). // Subprocess exit codes (positive integers like 1, 2, etc.) must not be used as JSON-RPC // error codes, as that would produce non-conformant responses (e.g. "code=1"). - const code = e && Number.isInteger(e.code) && e.code < 0 ? e.code : -32603; + const code = e && typeof e === "object" && Number.isInteger(e.code) && e.code < 0 ? e.code : -32603; server.replyError(id, code, e && e.message ? String(e.message) : "Internal error"); } } diff --git a/actions/setup/js/mcp_server_core.test.cjs b/actions/setup/js/mcp_server_core.test.cjs index 41153ebd6dc..fb27feedc55 100644 --- a/actions/setup/js/mcp_server_core.test.cjs +++ b/actions/setup/js/mcp_server_core.test.cjs @@ -545,7 +545,7 @@ describe("mcp_server_core.cjs", () => { expect(results[0].error.message).toBe("process exited with code 1"); }); - it("should fall back to -32603 and Internal error for thrown plain object without message", async () => { + it("should use Internal error when thrown plain object has no message property", async () => { const { registerTool, handleMessage } = await import("./mcp_server_core.cjs"); registerTool(server, {