Skip to content

fix(@angular/cli): batch Prettier invocations during migration formatting#33598

Open
mdlufy wants to merge 1 commit into
angular:mainfrom
mdlufy:fix/prettier-format-batching
Open

fix(@angular/cli): batch Prettier invocations during migration formatting#33598
mdlufy wants to merge 1 commit into
angular:mainfrom
mdlufy:fix/prettier-format-batching

Conversation

@mdlufy

@mdlufy mdlufy commented Jul 17, 2026

Copy link
Copy Markdown

Fixes #33597

Problem

formatFiles (packages/angular/cli/src/utilities/prettier.ts) passes every changed file to Prettier as a single execFile argument list:

await execFileAsync(
  process.execPath,
  [prettierCliPath, '--write', '--no-error-on-unmatched-pattern', '--ignore-unknown', ...files],
  { cwd, shell: false },
);

On large repositories (Nx monorepos, migrations touching thousands of files) the combined command line exceeds the OS limit and the spawn is rejected:

  • Windows → spawn ENAMETOOLONG (CreateProcess command line capped at 32,767 chars)
  • Linux / macOS → spawn E2BIG (argv+envp over ARG_MAX)

The error is caught and only logged, so ng update prints WARNING: Formatting of files failed with the following error: spawn ENAMETOOLONG and silently skips formatting — on exactly the large repos where the migration formatting step is most useful.

Reproduced on Node 26 / macOS (ARG_MAX 1 MiB): 25,000 changed paths ≈ 2 MB of argv → spawn E2BIG.

Fix

Split the file list into batches whose combined argument length stays under a conservative cross-platform budget (32_000, below the Windows 32,767 limit and far below POSIX ARG_MAX), and invoke Prettier once per batch. A single file longer than the budget still gets its own batch, so no file is ever dropped.

The batching logic is extracted into a small pure helper (batchFilesByArgumentLength) so it can be unit-tested deterministically without spawning a process.

Tests

Added prettier_spec.ts covering: empty input, single batch, splitting when the budget is exceeded, reserving the base-argument length in every batch, never dropping an oversized file, and keeping multi-file batches within budget for a 5,000-file set.

Notes

Related but different (already-fixed) code path: angular/angular#57978 (ng build spawn ENAMETOOLONG from many uncommitted files, in compiler-cli).

@google-cla

google-cla Bot commented Jul 17, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a batching mechanism to group files when executing Prettier, preventing command-line length limit issues (such as on Windows) when formatting a large number of files. Unit tests have also been added to verify the batching logic. The review feedback suggests improving the accuracy of the command-line length calculation by accounting for argument quoting when paths contain spaces, including the Node executable path in the base length, and adding a corresponding unit test.

Comment thread packages/angular/cli/src/utilities/prettier.ts Outdated
Comment thread packages/angular/cli/src/utilities/prettier.ts Outdated
Comment thread packages/angular/cli/src/utilities/prettier_spec.ts
@mdlufy
mdlufy force-pushed the fix/prettier-format-batching branch from 2c83cc9 to 64ba971 Compare July 17, 2026 07:59
@mdlufy

mdlufy commented Jul 17, 2026

Copy link
Copy Markdown
Author

Thanks for the review! Addressed all three points:

  • Quoting for spaces — per-file length now adds the surrounding quotes the OS applies to paths containing spaces (file.length + (file.includes(' ') ? 3 : 1)).
  • process.execPath in the base length — good catch; it's spawned as the first argument and counts toward the limit, so baseLength now includes it (and applies the same quoting rule to it and prettierCliPath).
  • Test — added a case covering the extra length reserved for space-containing paths.

Verified the batching against the repro from #33597 (25k paths on macOS ARG_MAX 1 MiB) — runs across multiple spawns with no E2BIG/ENAMETOOLONG.

@mdlufy
mdlufy force-pushed the fix/prettier-format-batching branch from 64ba971 to 7512ea5 Compare July 17, 2026 08:12
@mdlufy

mdlufy commented Jul 17, 2026

Copy link
Copy Markdown
Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces batching for files formatted via Prettier to prevent exceeding the OS command-line length limit, adding a helper function batchFilesByArgumentLength along with comprehensive unit tests. The feedback highlights an issue where a failure in an early batch would abort the entire formatting process; catching and aggregating errors across all batches is recommended to preserve the original behavior.

Comment thread packages/angular/cli/src/utilities/prettier.ts
…ting

`formatFiles` passed every changed file to Prettier as a single `execFile`
argument list. On large repositories (thousands of changed files) the combined
command line exceeds the OS limit and the spawn is rejected with `spawn E2BIG`
(POSIX) or `spawn ENAMETOOLONG` (Windows). The error is caught and only logged,
so `ng update` migrations print `WARNING: Formatting of files failed ...` and
silently skip formatting on exactly the large repos the step targets.

Split the file list into batches that stay under a conservative command-line
length budget and invoke Prettier once per batch.

Fixes angular#33597
@mdlufy
mdlufy force-pushed the fix/prettier-format-batching branch from 7512ea5 to 14530ef Compare July 17, 2026 11:28
@mdlufy

mdlufy commented Jul 17, 2026

Copy link
Copy Markdown
Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a batching mechanism to group files by argument length before executing Prettier, preventing command-line length limit issues (such as E2BIG or ENAMETOOLONG) on systems like Windows when formatting a large number of files. It also adds comprehensive unit tests to verify the batching logic under various conditions. There are no review comments to address, and I have no additional feedback to provide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ng update: formatFiles fails with spawn ENAMETOOLONG/E2BIG on large repos (all files passed as one argv)

1 participant