diff --git a/.changeset/patch-fix-create-pr-enobufs.md b/.changeset/patch-fix-create-pr-enobufs.md new file mode 100644 index 00000000000..e3e006f3c17 --- /dev/null +++ b/.changeset/patch-fix-create-pr-enobufs.md @@ -0,0 +1,12 @@ +--- +"gh-aw": patch +--- + +Fixed `create_pull_request` failing with `spawnSync git ENOBUFS` on large diffs (e.g. 47+ changed files). + +The `execGitSync` helper in `git_helpers.cjs` used Node.js `spawnSync` without an explicit `maxBuffer`, defaulting to ~1 MB. When `git format-patch --stdout` produced output exceeding that limit, all patch generation strategies silently failed with a misleading "No changes to commit" error. + +The fix: +- Set `maxBuffer: 100 * 1024 * 1024` (100 MB) as the default in `execGitSync`, matching the `max_patch_size` headroom and consistent with other handlers in the codebase (e.g. MCP handlers use 10 MB). +- Detect `ENOBUFS` errors and throw an actionable error message that surfaces the real cause instead of the generic "no commits found" fallback. +- Callers can still override `maxBuffer` via the options spread. diff --git a/actions/setup/js/git_helpers.cjs b/actions/setup/js/git_helpers.cjs index 84bf2b65630..c7013a7bcb5 100644 --- a/actions/setup/js/git_helpers.cjs +++ b/actions/setup/js/git_helpers.cjs @@ -66,10 +66,18 @@ function execGitSync(args, options = {}) { const result = spawnSync("git", args, { encoding: "utf8", + maxBuffer: 100 * 1024 * 1024, // 100 MB — prevents ENOBUFS on large diffs (e.g. git format-patch) ...spawnOptions, }); if (result.error) { + // Detect ENOBUFS (buffer overflow) and provide a more actionable message + if (result.error.code === "ENOBUFS") { + const bufferError = new Error(`${ERR_SYSTEM}: Git command output exceeded buffer limit (ENOBUFS). The output from '${args[0]}' is too large for the configured maxBuffer. Consider reducing the diff size or increasing maxBuffer.`); + bufferError.code = "ENOBUFS"; + core.error(`Git command buffer overflow: ${gitCommand}`); + throw bufferError; + } // Spawn-level errors (e.g. ENOENT, EACCES) are always unexpected — log // via core.error regardless of suppressLogs. core.error(`Git command failed with error: ${result.error.message}`); diff --git a/actions/setup/js/git_helpers.test.cjs b/actions/setup/js/git_helpers.test.cjs index 04d35c76e20..63f5d886a06 100644 --- a/actions/setup/js/git_helpers.test.cjs +++ b/actions/setup/js/git_helpers.test.cjs @@ -80,6 +80,15 @@ describe("git_helpers.cjs", () => { expect(result).toContain("git version"); }); + it("should throw actionable ENOBUFS error when maxBuffer is exceeded", async () => { + const { execGitSync } = await import("./git_helpers.cjs"); + + // Use a tiny maxBuffer to trigger ENOBUFS on any git output + expect(() => { + execGitSync(["--version"], { maxBuffer: 1 }); + }).toThrow(/ENOBUFS|buffer limit/i); + }); + it("should return stdout from successful commands", async () => { const { execGitSync } = await import("./git_helpers.cjs");