Skip to content

fix(actions): stop a killed npm upgrade wedging an agent for good - #8

Merged
forgetso merged 1 commit into
mainfrom
fix/npm-global-install-enotempty
Sep 25, 2026
Merged

forgetso merged 1 commit into
mainfrom
fix/npm-global-install-enotempty

Conversation

@forgetso

Copy link
Copy Markdown
Member

What was broken

Every job that landed on the self-hosted agent prosvr8-3 failed at the install npm step with exit code 217:

npm error ENOTEMPTY: directory not empty, rename
  '.../lib/node_modules/npm' -> '.../lib/node_modules/.npm-YceoXqXY'

4 of the last 12 failed runs on Protect were this. All of them that one agent.

Why

npm i -g npm upgrades npm by renaming the live node_modules/npm directory out of the way to .npm-<suffix>, then unpacking the new copy in its place. That suffix comes from the path, not from a random number.

So when an upgrade gets killed part-way — a cancelled run, an agent restart — it leaves the half-copied .npm-<suffix> directory sitting there. The next upgrade picks the same name, and renaming onto a non-empty directory is ENOTEMPTY. Every time. The agent is broken until someone SSHes in and deletes it by hand.

prosvr8-3 had one dated 2026-09-24 12:12 and failed this step on every job it picked up for a day. (Already cleared by hand, so CI is unblocked; this PR stops it happening again.)

The sting: npm on that agent was already 11.6.2. The step was reinstalling a version it already had, and wedging itself doing it.

What changed

Test coverage

No tests in this repo. Verified directly against the real agent:

  • npm prefix -g resolves to the toolcache root, so the sweep path ($(npm prefix -g)/lib/node_modules/.npm-*) is the right directory.
  • The skip branch fires on an agent already at 11.6.2.
  • YAML parses; .npm-* matching nothing is a no-op under rm -rf.
  • The 4 previously-wedged Protect runs were re-run and the npm@ step now reports success.

🤖 Generated with Claude Code

`npm i -g npm` renames the live npm directory aside to `.npm-<suffix>`
before unpacking the new one. The suffix is derived from the path, not
random, so an install killed part-way leaves that directory behind and
every later install on the same agent fails the rename with ENOTEMPTY.
The agent stays broken until someone deletes it by hand -- prosvr8-3 sat
like that from 2026-09-24 and failed this step on every job it picked up.

Skip the install when npm is already the pinned version, which on a
self-hosted agent is every run after the first, and sweep any leftover
staging directory before installing for the agents already holding one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@forgetso
forgetso merged commit 1e2f6e3 into main Sep 25, 2026
1 check passed
@forgetso
forgetso deleted the fix/npm-global-install-enotempty branch September 25, 2026 09:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant