{"record":{"id":"98948bdd6f690963","repo":"windmill-labs/windmill","slug":"npm-exited-with-exitcode-null-a-signal","errorCode":null,"errorMessage":"npm exited with ${exitCode === null ? \"a signal\" : `code ${exitCode}`}${detail ? `:\n${detail}` : \"\"}\n\n${HINT}","messagePattern":"npm exited with (.+?)`\\}(.+?)` : \"\"\\}\n\n(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/src/utils/upgrade.ts","lineNumber":111,"sourceCode":"      output.push(String(d));\n      if (verbose) process.stderr.write(d);\n    });\n    // `error` fires when npm can't be spawned at all; without a listener that\n    // is an uncaught exception, crashing before any hint prints. `close`\n    // resolves null when npm died from a signal — a failure too.\n    const exitCode: number | null = await new Promise<number | null>(\n      (resolve, reject) => {\n        proc.on(\"error\", reject);\n        proc.on(\"close\", resolve);\n      }\n    ).catch((e) => {\n      throw new Error(\n        `failed to run npm: ${e instanceof Error ? e.message : e}\\n\\n${HINT}`\n      );\n    });\n    if (exitCode !== 0) {\n      const detail = output.join(\"\").trim();\n      throw new Error(\n        `npm exited with ${\n          exitCode === null ? \"a signal\" : `code ${exitCode}`\n        }${detail ? `:\\n${detail}` : \"\"}\\n\\n${HINT}`\n      );\n    }\n  }\n}\n\ntype NpmApiPackageMetadata = {\n  \"dist-tags\": {\n    latest: string;\n  };\n  versions: {\n    [version: string]: unknown;\n  };\n};\n","sourceCodeStart":93,"sourceCodeEnd":128,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/cli/src/utils/upgrade.ts#L93-L128","documentation":"Thrown by the windmill CLI's `upgrade` function when the spawned npm process completes but exits with a non-zero code (or is killed by a signal). The npm stdout/stderr output is appended to the message so the real cause (permissions, network, registry errors) is visible.","triggerScenarios":"Running `wmill upgrade` when `npm install -g windmill-cli@latest` fails: no write permission to the global node_modules, network/registry outage, or npm peer-dependency conflicts.","commonSituations":"Global installs requiring sudo (EACCES); corporate proxies blocking registry.npmjs.org; interrupted install leaving npm in a bad state; Windows file locks on the binary being replaced.","solutions":["Read the `detail` section of the message for npm's actual error and fix it (e.g. EACCES → fix npm prefix or use a node version manager)","Upgrade manually: `npm install -g windmill-cli@latest` (with sudo only if unavoidable)","Check network/proxy access to the npm registry (`npm ping`), then retry `wmill upgrade`"],"exampleFix":"// before\nwmill upgrade\n// npm exited with code 1:\n// EACCES: permission denied ...\n// after (permission fix)\nnpm config set prefix ~/.npm-global\nexport PATH=\"$HOME/.npm-global/bin:$PATH\"\nwmill upgrade","handlingStrategy":"try-catch","validationCode":"const probe = spawnSync('npm', ['ping'], { stdio: 'ignore' });\nif (probe.status !== 0) throw new Error('npm registry unreachable; fix network/proxy before upgrading');","typeGuard":null,"tryCatchPattern":"try {\n  await upgrade();\n} catch (e) {\n  if (e.message.startsWith('npm exited with')) {\n    // npm output follows the colon; surface it to the user\n    console.error(e.message);\n    console.error('Run `npm install -g windmill-cli@latest` manually and retry.');\n  } else throw e;\n}","preventionTips":["Ensure the npm global prefix is writable (or use a version manager) before upgrading","Check registry connectivity (`npm ping`) behind corporate proxies","Don't run the upgrade while another npm install holds locks"],"tags":["cli","npm","upgrade","process-exit","permissions"],"backgroundTag":"npm-install-failed","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}