cli
cli copied to clipboard
[[email protected]] spawn E2BIG or ENAMETOOLONG
What happened?
When I run yarn exec code-pushup collect --config=code-pushup.config.ts in a large Nx 17.1.3 workspace with Angular 16.2.12 (+500,000 LOC, ~500 Nx projects), I get:
spawn E2BIGerror in thenode:18container image (Debian 12.4 "Bookworm") in GitLab CIspawn ENAMETOOLONGerror locally on Windows.
Code PushUp configuration:
import eslintPlugin, {
eslintConfigFromNxProjects,
} from '@code-pushup/eslint-plugin';
import { CoreConfig } from '@code-pushup/models';
export default {
persist: {
outputDir: 'dist/.code-pushup',
format: ['json', 'md'],
},
plugins: [await eslintPlugin(await eslintConfigFromNxProjects())],
categories: [
{
slug: 'bug-prevention',
title: 'Bug prevention',
refs: [
{
type: 'group',
plugin: 'eslint',
slug: 'problems',
weight: 100,
},
],
},
{
slug: 'code-style',
title: 'Code style',
refs: [
{
type: 'group',
plugin: 'eslint',
slug: 'suggestions',
weight: 75,
},
{
type: 'group',
plugin: 'eslint',
slug: 'formatting',
weight: 25,
},
],
},
],
} satisfies CoreConfig;
What would you expect to happen?
The yarn exec code-pushup collect --config=code-pushup.config.ts command should work no matter the codebase size or length of paths.
What steps did you take?
- Add Code PushUp to a large Nx 17.1.3 workspace with Angular 16.2.12 (+500,000 LOC, ~500 Nx projects)
- Run
yarn exec code-pushup collect --config=code-pushup.config.ts
What operation system are you on?
Windows
Node version
18.19.0
Relevant log output
node:18
Code PushUp CLI
Run collect...
Run Plugins: 0% |
Run Plugins: 0% | Executing ESLint
Run Plugins: ████████████████████████████████████████ 100% | Executing ESLint
Run Plugins: ████████████████████████████████████████ 100% | Done running plugins
Plugins failed:
spawn E2BIG
Error: Plugins failed: 1 errors: spawn E2BIG
at executePlugins (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:1644:11)
at async collect (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:1673:25)
at async collectAndPersistReports (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:1796:18)
at async handler (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:1880:7)
at async Object.handler (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:1997:14)
code-pushup collect
Run Plugins and collect results
Options:
--progress Show progress bar in stdout.
[boolean] [default: true]
--verbose When true creates more verbose output. This is help
ful when debugging. [boolean] [default: false]
--config Path the the config file, e.g. code-pushup.config.j
s [string] [default: "code-pushup.config.js"]
--persist.outputDir Directory for the produced reports [string]
--persist.filename Filename for the produced reports. [string]
--persist.format Format of the report output. e.g. `md`, `json`
[array]
--upload.organization Organization slug from portal [string]
--upload.project Project slug from portal [string]
--upload.server URL to your portal server [string]
--upload.apiKey API key for the portal server [string]
--onlyPlugins List of plugins to run. If not set all plugins are
run. [array] [default: []]
-h, --help Show help [boolean]
Error: Plugins failed: 1 errors: spawn E2BIG
at executePlugins (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:1644:11)
at async collect (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:1673:25)
at async collectAndPersistReports (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:1796:18)
at async handler (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:1880:7)
at async Object.handler (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:1997:14)
Windows 11
Code PushUp CLI
Run collect...
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Run Plugins: ████████████████████████████████████████ 100% | Done running plugins
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Plugins failed:
spawn ENAMETOOLONG
Error: Plugins failed: 1 errors: spawn ENAMETOOLONG
at executePlugins (file:///D:/projects/xxx/node_modules/@code-pushup/cli/index.js:1644:11)
at async collect (file:///D:/projects/xxx/node_modules/@code-pushup/cli/index.js:1673:25)
at async collectAndPersistReports (file:///D:/projects/xxx/node_modules/@code-pushup/cli/index.js:1796:18)
at async handler (file:///D:/projects/xxx/node_modules/@code-pushup/cli/index.js:1880:7)
at async Object.handler (file:///D:/projects/xxx/node_modules/@code-pushup/cli/index.js:1997:14)
code-pushup collect
Run Plugins and collect results
Options:
--progress Show progress bar in stdout.
[boolean] [default: true]
--verbose When true creates more verbose output. This is help
ful when debugging. [boolean] [default: false]
--config Path the the config file, e.g. code-pushup.config.j
s [string] [default: "code-pushup.config.js"]
--persist.outputDir Directory for the produced reports [string]
--persist.filename Filename for the produced reports. [string]
--persist.format Format of the report output. e.g. `md`, `json`
[array]
--upload.organization Organization slug from portal [string]
--upload.project Project slug from portal [string]
--upload.server URL to your portal server [string]
--upload.apiKey API key for the portal server [string]
--onlyPlugins List of plugins to run. If not set all plugins are
run. [array] [default: []]
-h, --help Show help [boolean]
Error: Plugins failed: 1 errors: spawn ENAMETOOLONG
at executePlugins (file:///D:/projects/xxx/node_modules/@code-pushup/cli/index.js:1644:11)
at async collect (file:///D:/projects/xxx/node_modules/@code-pushup/cli/index.js:1673:25)
at async collectAndPersistReports (file:///D:/projects/xxx/node_modules/@code-pushup/cli/index.js:1796:18)
at async handler (file:///D:/projects/xxx/node_modules/@code-pushup/cli/index.js:1880:7)
at async Object.handler (file:///D:/projects/xxx/node_modules/@code-pushup/cli/index.js:1997:14)
We will need to setup testing repository with significant amount of Nx projects to debug this as we do not see this issues on currently connected projects.
@LayZeeDK Is there anything else you'd be able to share to help us debug this?
@LayZeeDK
In the past it helped me to set git config --global core.longpaths true for longer paths to be handled correctly on Windows.
Please let us know if this works for you 🙏
No, that's not it.
could be related: https://github.com/nrwl/nx/issues/8646
Node.js outputs E2BIG when ERROR_META_EXPANSION_TOO_LONG is raised by Windows or for certain path operations, meaning
The global filename characters, * or ?, are entered incorrectly or too many global filename characters are specified.
according to OS documentation/source code, or
Indicates that the list of arguments is longer than expected.
according to Node.js documentation
Possibly tweaked via ARG_MAX (run getconf ARG_MAX to check current setting).
Node.js outputs ENAMETOOLONG when ERROR_FILENAME_EXCED_RANGE is raised by Windows, meaning
The filename or extension is too long.
according to Windows documentation, or
Indicates that the filename is too long.
according to Node.js documentation
The only published Code PushUp CLI code that uses spawn is executeProcess
https://github.com/code-pushup/cli/blob/79dfce700e3dfc5af2a7bbc303c9a5fb12ee16a3/packages/utils/src/lib/execute-process.ts#L142
executeProcess is called by:
executeRunnerConfighttps://github.com/code-pushup/cli/blob/79dfce700e3dfc5af2a7bbc303c9a5fb12ee16a3/packages/core/src/lib/implementation/runner.ts#L18-L22- Coverage plugin https://github.com/code-pushup/cli/blob/79dfce700e3dfc5af2a7bbc303c9a5fb12ee16a3/packages/plugin-coverage/src/lib/runner/index.ts#L25
executeRunnerConfig is called by executePlugin
https://github.com/code-pushup/cli/blob/79dfce700e3dfc5af2a7bbc303c9a5fb12ee16a3/packages/core/src/lib/implementation/execute-plugin.ts#L67
executePlugin is called by executePlugins
https://github.com/code-pushup/cli/blob/79dfce700e3dfc5af2a7bbc303c9a5fb12ee16a3/packages/core/src/lib/implementation/execute-plugin.ts#L131
executePlugins is called by collect
https://github.com/code-pushup/cli/blob/79dfce700e3dfc5af2a7bbc303c9a5fb12ee16a3/packages/core/src/lib/implementation/collect.ts#L20
collect is called by collectAndPersistReports
https://github.com/code-pushup/cli/blob/79dfce700e3dfc5af2a7bbc303c9a5fb12ee16a3/packages/core/src/lib/collect-and-persist.ts#L18
collectAndPersistReports is called by:
yargsCollectCommandObjecthttps://github.com/code-pushup/cli/blob/79dfce700e3dfc5af2a7bbc303c9a5fb12ee16a3/packages/cli/src/lib/collect/collect-command.ts#L27yargsAutorunCommandObjecthttps://github.com/code-pushup/cli/blob/79dfce700e3dfc5af2a7bbc303c9a5fb12ee16a3/packages/cli/src/lib/autorun/autorun-command.ts#L44
What do you suggest as a next step here? If I understand correctly is that we should not use spawn?
Maybe but it's difficult to tell until we know how to reproduce this issue. Maybe it's as simple as trying long project/file names.
Could this possibly be related to #529? I plan to fix that by having the ESLint plugin use a temporary file instead of command-line args.
Since https://github.com/code-pushup/cli/issues/529 was fixed please let us know if the issues still persist 🙂
Thanks, I will schedule to try the latest version at work 2 weeks from now.
I tested this in our monorepo with Code PushUp version 0.35.0 and the E2BIG and ENAMETOOLONG errors are gone both locally on Windows and in CI on Debian so this issue can be closed at least when it comes to the original error codes.
However, now the code-pushup collect command causes Node.js to run out of memory. Is there a way to limit how many Node.js processes that are spawned/executed in parallel?
Out-of-memory example
Code PushUp CLI
[ info ] Run collect...
Run plugins: 0% |
Run plugins: 0% | Executing ESLint
Run plugins: ████████████████████████████████████████████████████████████████████████████████ 100% | Executing ESLint
Run plugins: ████████████████████████████████████████████████████████████████████████████████ 100% | Done running plugins
[ warn ] Plugins failed:
[ warn ]
<--- Last few GCs --->
[638:0x598f850] 758934 ms: Scavenge 4034.0 (4119.3) -> 4033.2 (4128.8) MB, 15.2 / 0.0 ms (average mu = 0.798, current mu = 0.700) allocation failure;
[638:0x598f850] 758977 ms: Scavenge 4039.6 (4128.8) -> 4037.4 (4129.8) MB, 19.1 / 0.0 ms (average mu = 0.798, current mu = 0.700) allocation failure;
[638:0x598f850] 760021 ms: Scavenge 4040.9 (4129.8) -> 4039.3 (4149.3) MB, 1029.9 / 0.0 ms (average mu = 0.798, current mu = 0.700) allocation failure;
<--- JS stacktrace --->
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
1: 0xb9a300 node::Abort() [/usr/local/bin/node]
2: 0xaa0794 [/usr/local/bin/node]
3: 0xd71e20 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]
4: 0xd721c7 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]
5: 0xf4f585 [/usr/local/bin/node]
6: 0xf61a5d v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/usr/local/bin/node]
7: 0xf3c14e v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/usr/local/bin/node]
8: 0xf3d517 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/usr/local/bin/node]
9: 0xf1e71a v8::internal::Factory::NewFillerObject(int, v8::internal::AllocationAlignment, v8::internal::AllocationType, v8::internal::AllocationOrigin) [/usr/local/bin/node]
10: 0x12e396f v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [/usr/local/bin/node]
11: 0x1710679 [/usr/local/bin/node]
Aborted
Error: Plugins failed: 1 errors:
<--- Last few GCs --->
[638:0x598f850] 758934 ms: Scavenge 4034.0 (4119.3) -> 4033.2 (4128.8) MB, 15.2 / 0.0 ms (average mu = 0.798, current mu = 0.700) allocation failure;
[638:0x598f850] 758977 ms: Scavenge 4039.6 (4128.8) -> 4037.4 (4129.8) MB, 19.1 / 0.0 ms (average mu = 0.798, current mu = 0.700) allocation failure;
[638:0x598f850] 760021 ms: Scavenge 4040.9 (4129.8) -> 4039.3 (4149.3) MB, 1029.9 / 0.0 ms (average mu = 0.798, current mu = 0.700) allocation failure;
<--- JS stacktrace --->
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
1: 0xb9a300 node::Abort() [/usr/local/bin/node]
2: 0xaa0794 [/usr/local/bin/node]
3: 0xd71e20 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]
4: 0xd721c7 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]
5: 0xf4f585 [/usr/local/bin/node]
6: 0xf61a5d v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/usr/local/bin/node]
7: 0xf3c14e v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/usr/local/bin/node]
8: 0xf3d517 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/usr/local/bin/node]
9: 0xf1e71a v8::internal::Factory::NewFillerObject(int, v8::internal::AllocationAlignment, v8::internal::AllocationType, v8::internal::AllocationOrigin) [/usr/local/bin/node]
10: 0x12e396f v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [/usr/local/bin/node]
11: 0x1710679 [/usr/local/bin/node]
Aborted
at executePlugins (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:2183:11)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async collect (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:2206:25)
at async collectAndPersistReports (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:2279:18)
at async handler (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:2746:7)
at async Object.handler (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:2830:14)
code-pushup collect
Run Plugins and collect results
Global Options:
--progress Show progress bar in stdout. [boolean] [default: true]
--verbose When true creates more verbose output. This is helpful when
debugging. [boolean] [default: false]
--config Path to config file, e.g. code-pushup.config.ts. By default
it loads code-pushup.config.(ts|mjs|js). [string]
--tsconfig Path to a TypeScript config, to be used when loading config
file. [string]
--onlyPlugins List of plugins to run. If not set all plugins are run.
[array] [default: []]
Persist Options:
--persist.outputDir Directory for the produced reports [string]
--persist.filename Filename for the produced reports. [string]
--persist.format Format of the report output. e.g. `md`, `json`[array]
Upload Options:
--upload.organization Organization slug from portal [string]
--upload.project Project slug from portal [string]
--upload.server URL to your portal server [string]
--upload.apiKey API key for the portal server [string]
Options:
-h, --help Show help [boolean]
Error: Plugins failed: 1 errors:
<--- Last few GCs --->
[638:0x598f850] 758934 ms: Scavenge 4034.0 (4119.3) -> 4033.2 (4128.8) MB, 15.2 / 0.0 ms (average mu = 0.798, current mu = 0.700) allocation failure;
[638:0x598f850] 758977 ms: Scavenge 4039.6 (4128.8) -> 4037.4 (4129.8) MB, 19.1 / 0.0 ms (average mu = 0.798, current mu = 0.700) allocation failure;
[638:0x598f850] 760021 ms: Scavenge 4040.9 (4129.8) -> 4039.3 (4149.3) MB, 1029.9 / 0.0 ms (average mu = 0.798, current mu = 0.700) allocation failure;
<--- JS stacktrace --->
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
1: 0xb9a300 node::Abort() [/usr/local/bin/node]
2: 0xaa0794 [/usr/local/bin/node]
3: 0xd71e20 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]
4: 0xd721c7 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]
5: 0xf4f585 [/usr/local/bin/node]
6: 0xf61a5d v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/usr/local/bin/node]
7: 0xf3c14e v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/usr/local/bin/node]
8: 0xf3d517 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/usr/local/bin/node]
9: 0xf1e71a v8::internal::Factory::NewFillerObject(int, v8::internal::AllocationAlignment, v8::internal::AllocationType, v8::internal::AllocationOrigin) [/usr/local/bin/node]
10: 0x12e396f v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [/usr/local/bin/node]
11: 0x1710679 [/usr/local/bin/node]
Aborted
at executePlugins (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:2183:11)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async collect (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:2206:25)
at async collectAndPersistReports (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:2279:18)
at async handler (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:2746:7)
at async Object.handler (file:///builds/xxx/node_modules/@code-pushup/cli/index.js:2830:14)
I have tried both lowering and increasing the memory limit per Node.js process by changing environment variable NODE_OPTIONS=--max-old-space-size=4096 (the default as an example).
Is there a way to limit how many Node.js processes that are executed in parallel?
We actually don't do any parallel execution at the moment, all plugins are run sequentially.
I have tried both lowering and increasing the memory limit per Node.js process by changing environment variable NODE_OPTIONS=--max-old-space-size=4096 (the default as an example).
In some of our codebases we use NODE_OPTIONS=--max-old-space-size=8192.
Linting with type information is known to impact ESLint speed in large repos, perhaps you could try if disabling these rules helps with the memory size.
Another option if your monorepo is really large is to separate into many Code PushUp projects. We have some docs on this setup in our Nx integration guide - expand the Alternatives to linting all Nx projects at once section.
A future optimization I have in mind is to run ESLint itself in parallel, which should bring significant speed improvements for large codebases.
Thank you, @matejchalk.
Both locally and in CI, I have tried to increase the Node.js process memory limit to 16 GB RAM. As mentioned, we lint more than 500,000 LOC. Yes, we do have type-aware ESLint rules and we are not looking to disable them. I might try it but it will require disabling them across 520 TypeScript configurations which is a bit of a pain.
It would be great to be able to split the linting of my Nx projects into several chunks/shards/runners. The Alternatives to linting all Nx projects at once documentation suggest either:
- Split by entry point. Not an option as we currently only have one application project which has dependencies to all 520 Nx libraries with a few exceptions like test utilities.
- A Code PushUp configuration for each project, creating a report per project. This would require a lot of boilerplate. An Nx generator could be created for convenience. We would be able to track metrics on the library level but we wouldn't be able to get an overview of the entire codebase even though it's a single application project. Maybe we could structure our codebase in a way that each domain has a single entry point but this requires a huge refactor.
I will probably try:
- Disabling type-aware lint rules (although these are as important as other lint rules)
- Creating a Code PushUp configuration for a subset of the application and see how much value this brings (if it works) although I would expect a tool like this to be scalable for enterprise applications, ideally out-of-the-box.
- Evaluating alternatives, for example Sourcegraph Code Insights and Betterer
@LayZeeDK Thanks for explaining your use case.
I think the memory error could be resolved if we lint projects separately instead of all at once - added more info in #629.
A Code PushUp configuration for each project, creating a report per project. This would require a lot of boilerplate. An Nx generator could be created for convenience.
We actually have an Nx configuration generator in progress - cc @BioPhoton.
HI @LayZeeDK We have a PR (will take some time to merge it, but it is working) that can set up CP and run it per project.
If you are interested to try it before it is released lets chat up!
branch is here: https://github.com/code-pushup/cli/tree/add-createNodes-api-to-nx-plugin
@LayZeeDK I've just released version 0.39.0 of our ESLint plugin, with the memory consumption improvements implemented in #629. This change enabled us to remove NODE_OPTIONS=--max-old-space-size=8192 in our Nx monorepo (uses the all-in-one approach). Please let me know if it resolves the issue on your end :pray:
Thank you for your continued work on this project and this issue, @matejchalk and @BioPhoton! ❤️
I'm pleased to report that after updating to version 0.49.0 and eslintConfigFromAllNxProjects, I got Code PushUp CLI with the ESLint plugin running in our large Nx+Angular monorepo for the first time! 🙌
It ran with type-aware lint rules and the CI run time was 1h15m.
There was only one undocumented requirement: I had to install the bundle-require package after receiving the following error message.
node:internal/errors:496
ErrorCaptureStackTrace(err);
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'bundle-require' imported from /builds/xxx/node_modules/@code-pushup/cli/index.js
at new NodeError (node:internal/errors:405:5)
at packageResolve (node:internal/modules/esm/resolve:916:9)
at moduleResolve (node:internal/modules/esm/resolve:973:20)
at defaultResolve (node:internal/modules/esm/resolve:1193:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:403:12)
at ModuleLoader.resolve (node:internal/modules/esm/loader:372:25)
at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:249:38)
at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:39)
at link (node:internal/modules/esm/module_job:75:36) {
code: 'ERR_MODULE_NOT_FOUND'
}
Node.js v18.19.0