Spago fails to build on Windows and Node v 21.7
On linux everything works fine, but on my Windows machine, spago fails to build on Node 21.7 with
node:internal/child_process:421
throw new ErrnoException(err, 'spawn');
^
Error: spawn EINVAL
at ChildProcess.spawn (node:internal/child_process:421:11)
at Object.spawn (node:child_process:761:9)
at C:\Git\WebPlatform\node_modules\purescript-psa\output\Node.ChildProcess\foreign.js:16:49
at __do (C:\Git\WebPlatform\node_modules\purescript-psa\output\Main\index.js:545:27)
at ChildProcess.<anonymous> (C:\Git\WebPlatform\node_modules\purescript-psa\output\Node.ChildProcess\foreign.js:125:24)
at ChildProcess.emit (node:events:519:28)
at ChildProcess._handle.onexit (node:internal/child_process:292:12)
at onErrorNT (node:internal/child_process:484:16)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
errno: -4071,
code: 'EINVAL',
syscall: 'spawn'
}
Node.js v21.7.3
[error] Failed to build.
It works just fine on 21.6:
I'm not convinced the error is in spago itself, but in Node.js 21.7 I am able to do npx purs --version just fine (my machine is on purs version 0.15.15 and spago version 0.21.0)
The 0.21.x line is the legacy codebase, which is not maintained anymore. Would you be able to give this a try with spago@next?
spago@next seems to work with both versions of node (on a fresh project from spago init) 🎉. Is there anything to be concerned with if we switch to spago@next for production use? I notice it says it's still in alpha.
Good to know that the new spago works!
It's not alpha in the sense that "things are changing all the time" anymore, but more like "it still has paper cuts that we should fix before calling it ready for general usage"
We are using it in production at work, but YMMV. And if you do use it, please report weird things as soon as possible so we can get them fixed 🙂
That said, I'll close this ticket as it doesn't affect the new spago (which is now living in this repo)
I ran into this problem as well on Windows 10 and it seems to affect the new version of spago. I'm using spago 0.93.39 and Node.js v20.17.0. Spawn
The problematic call is this one
// spago/bin/bundle.js:85269
var spawn$prime = function() {
return function(command2) {
return function(args) {
return function(opts) {
return function() {
return spawn2(command2, args, opts);
};
};
};
};
};
It's probably connected to this
Can confirm this also happens on spago 0.93.40
I'll reopen this since it seems to be a recurring issue - we should try to find a way to replicate this in CI so we can issue a reasonable fix.
Is there any workaround we could do other than downgrade the system nodejs? Anywhere we could pass a --security-reverts flag when invoking spago? I looked around but couldn't find any.
We are using Node 22 in CI: https://github.com/purescript/spago/blob/b13857dcae4c908af20f5ad010b2581f6a4bab75/.github/workflows/build.yml#L38-L41
So I wonder if there's something else at play here?
I can confirm I am running Node v22.9.0, and have this issue, so maybe that isn't it.
I don't think the issue has been brought up here, but maybe this has to do with the args passed to the spawn command?
https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2
Could be related, and has caused similar issues for other projects in windows since the patch rolled out in all release lines, including purescript-lsp-server on my machine, which recently got fixed.
Here's the command, arguments to the command, and other options (including full environment variables and stack trace) of the spawn call that is causing the crash I'm experiencing. It appears in some installations, like mine (I'm using git bash and chocolatey on windows if it's any use), the purs compiler itself can be a .cmd file, meaning the shell option has to be used when calling it, otherwise an EINVAL error will happen. It appears spago is calling the purs compiler without this option, causing an immediate crash.
https://gist.github.com/AZMCode/616ac8a95ee5e1a93d4a92ce573d5658
Edit: Actually maybe this has to do with the path conversion Git Bash performs. I'll test that when I get the chance
Can confirm the bug doesn't happen outside of Git Bash
Should I open a new bug report?
Edit: Turns out I did test it with spago@next. This happens even when running outside of git bash
The issue starts right here https://github.com/purescript/spago/blob/b13857dcae4c908af20f5ad010b2581f6a4bab75/src/Spago/Cmd.purs#L182C1-L183C44
The desicion is taken to report a .cmd command path, but no information about whether, correspondingly, the shell flag should be used is reported to the exec command this return value is later used in.
Note that enabling the shell flag will inevitably introduce shell-interpretation bugs into the package manager. If the path for the filename or arguments is somehow malicious, arbitrary code could be executed. However, there is no choice but to do this if you're trying to run a '.cmd' in windows, as per the nodejs security release comments.
By the looks of what you're trying to execute, however, (Literally just 'purs.cmd' and the like) this shouldn't be an issue and the spawn flag could be enabled
The askVersion action in the same function makes the same mistake, which is what is crashing the package manager
In all honesty, I've given fixing it a good whirl, and I'm out of my depth here. I sure hope this error is eventually worked out so I can actually use purescript on my PC.
I think the spawn issue is what I've highlighted here so far, but this secondary issue I've encountered with futime while trying to fix the first one is keeping me from making any progress. Whenever the first issue is fixed, I'll report with a new issue regarding the second one if I still have it.
Ran into this trying to repro the CI failures on #1285. It's definitely caused by trying to invoke spawn on .cmd files, although I can't seem to directly prevent it with node's --security-revert flag so I'm not 100% sure when node "fixed" this behavior.
A proper fix would probably be doing some additional windows checks in Spago.Cmd;
- is host OS windows?
- does command we're about to run end in
.cmd? - (y) instead of
spawn(cmd, args)dospawn('cmd', [cmd, ...args])(or something like this)
This was on a fresh Windows 10 virtualbox image.
version things
Windows 10 Home 22H2
node 22.11.0
npm 10.9.0
purs 0.15.15
tried .cmd via `npm i -g purescript@latest`
and .exe via `npx purs-installer install --purs-version 0.15.15`
[email protected]
Hacky workaround if this is totally blocking your use of spago
I was able to temporarily bypass this by editing %APPDATA%\Roaming\npm\node_modules\spago\bin\bundle.js. Find a function spawnXXX (XXX are digits) that has "Failed pattern match at Spago.Cmd, and edit the options object passed to execa like so:
return bind37(execa(cmd)(args)(function(v) {
return {
cleanup: v.cleanup,
preferLocal: v.preferLocal,
stripFinalNewline: v.stripFinalNewline,
extendEnv: v.extendEnv,
env: v.env,
encoding: v.encoding,
argv0: v.argv0,
ipc: v.ipc,
stdioExtra: v.stdioExtra,
detached: v.detached,
uid: v.uid,
gid: v.gid,
timeout: v.timeout,
maxBuffer: v.maxBuffer,
windowsVerbatimArguments: v.windowsVerbatimArguments,
windowsHide: v.windowsHide,
windowsEnableCmdEcho: v.windowsEnableCmdEcho,
cwd: opts.cwd,
+ shell: new Just(true),
stdin: stdinOpt,
stdout: new Just(pipe2),
stderr: new Just(pipe2)
};
}))(function(subprocess) {
This unblocks being able to run spago build, but I think it breaks some other spawny things like bundle.
@AZMCode
Thanks for the effort, but applying a similar fix (I did it at the execa bindings level), I stumbled upon another bug. I could definitely give it a shot, but I'd have to bootstrap the compiler and it's a bit of a headache.
I've just ended up using codespaces due to other personal reasons, so this problem is not as bad for me now.
I would like to learn PureScript and was attempting to follow the instructions here. I installed 'spago@next' and updated Node to the latest version (via 'nvm'). Here is the feedback I get after executing 'spago init':
`--> spago init file:///D:/Programs/nvm/v23.3.0/node_modules/spago/bin/bundle.js:48911 throw util.fromLeft(step3); ^
Error: spawn EINVAL at ChildProcess.spawn (node:internal/child_process:421:11) at spawn (node:child_process:753:9) at file:///D:/Programs/nvm/v23.3.0/node_modules/spago/bin/bundle.js:83989:18 at runSync (file:///D:/Programs/nvm/v23.3.0/node_modules/spago/bin/bundle.js:48568:21) at run16 (file:///D:/Programs/nvm/v23.3.0/node_modules/spago/bin/bundle.js:48761:25) at file:///D:/Programs/nvm/v23.3.0/node_modules/spago/bin/bundle.js:48777:23 at drain (file:///D:/Programs/nvm/v23.3.0/node_modules/spago/bin/bundle.js:48595:9) at Object.enqueue (file:///D:/Programs/nvm/v23.3.0/node_modules/spago/bin/bundle.js:48613:11) at file:///D:/Programs/nvm/v23.3.0/node_modules/spago/bin/bundle.js:48771:31 at __do4 (file:///D:/Programs/nvm/v23.3.0/node_modules/spago/bin/bundle.js:86427:77) { errno: -4071, code: 'EINVAL', syscall: 'spawn' }
Node.js v23.3.0`
It sounds like I am being affected by the problem(s) described here in this thread. I am running on a Windows 10 box. I can give versions of various libraries I am using (such as 'git' or 'node' or 'spago' or whatever), if that might be useful.
I also have a Windows 11 box at work and get the exact same behavior there.