Skip to content

npx t3 service update fails with EALLOWSCRIPTS because npx exports npm_config_allow_scripts to the pinned runtime install #9398

Description

@0ut5ider

What happened

npx t3@nightly service update fails on Linux. The service stays on the old version.

The command prints this error:

ERROR (#5): BootServiceCommandError: Background setup failed while installing the pinned t3 runtime (this can take a few minutes) (exit code 1).
[cause]: PinnedRuntimeInstallError: Pinned runtime install failed while installing the pinned t3 runtime (this can take a few minutes) (exit code 1).

The error does not name the cause. The cause is in the npm debug log of the child install:

7 verbose title npm install t3@0.0.39-nightly.20260903.1268
8 verbose argv "install" "--prefix" "/home/outsider/.t3/runtime/versions/.staging-9O1QaD" "--no-fund" "--no-audit" "t3@0.0.39-nightly.20260903.1268"
13 error code EALLOWSCRIPTS
14 error --allow-scripts is not allowed in project-scoped installs. Add the entries to the "allowScripts" field in package.json, or to .npmrc, instead.

Note that argv holds no --allow-scripts flag.

Diagnosis

npx exports the resolved allow-scripts config to the child process as the environment variable npm_config_allow_scripts. The t3 command line interface (CLI) inherits this variable and passes it to the npm install --prefix <staging> child. npm 12 treats an environment variable as the env source. The function resolveAllowScripts in npm/lib/utils/resolve-allow-scripts.js throws EALLOWSCRIPTS when the policy comes from the cli source or the env source and the install is project-scoped.

This command shows the leak:

$ npx --yes node@22.22.3 -e 'console.log(process.env.npm_config_allow_scripts)'
node-pty
msgpackr-extract

Correction to PR #9380

PR #9380 says:

With allow-scripts=<other-package> in a user-level ~/.npmrc, npm 12 refuses every project-scoped install with EALLOWSCRIPTS (exit 1), manifest or not. That case now fails loudly at the install step instead of crash-looping; removing the stale key from ~/.npmrc is the fix on such a machine.

This is not correct. A user-level ~/.npmrc is the user source. resolveAllowScripts does not throw for the user source. It throws only for the cli source and the env source. The user does not need to remove the key.

I tested this on the machine that failed. I did not change ~/.npmrc. It still holds allow-scripts[]=node-pty and allow-scripts[]=msgpackr-extract. I started the same CLI without npx, so no npm_config_allow_scripts variable existed:

unset npm_config_allow_scripts
node ~/.npm/_npx/<hash>/node_modules/t3/dist/bin.mjs service update

Result:

Updated T3 Code service with t3@0.0.39-nightly.20260903.1268.

The install also compiled the native module, because the ~/.npmrc policy still applied as the .npmrc layer:

$ ls ~/.t3/runtime/versions/0.0.39-nightly.20260903.1268/node_modules/node-pty/build/Release/pty.node
.../build/Release/pty.node

The service now runs the new version and answers HTTP 200.

Steps to reproduce

Use a Linux machine with npm 12.

  1. Make sure that ~/.npmrc holds no allow-scripts key.
  2. Install the background service with npx t3@nightly service install.
  3. Add allow-scripts[]=node-pty to ~/.npmrc.
  4. Run npx t3@nightly service update.
  5. Read the newest file in ~/.npm/_logs/.

The order is important. service install and service update both call
ensurePinnedRuntimeInstalled, so an install that starts after step 3 fails in
the same way.

This reproduction does not need t3:

npm exec --yes -c 'npm install --prefix /tmp/x --no-fund --no-audit msgpackr-extract@3.0.4'

The command exits 1 with EALLOWSCRIPTS when ~/.npmrc holds a non-empty
allow-scripts value. The same command exits 0 when the inner shell first runs
unset npm_config_allow_scripts.

Suggested fix

Delete npm_config_allow_scripts from the environment of the child npm install in ensurePinnedRuntimeInstalled (apps/server/src/cloud/pinnedRuntime.ts). Delete every npm_config_* variable that npx exports, because each one can change the child install in a way the CLI does not intend.

The grant path then stays as PR #9380 designs it: the staged package.json manifest, plus the user .npmrc layer.

Also surface the child stderr in PinnedRuntimeInstallError. The npm error text is precise. The current message sends the user to the npm debug log to find it.

Workaround

Do not start the CLI with npx:

npm install --prefix ~/.cache/t3-updater --no-fund --no-audit t3@nightly
node ~/.cache/t3-updater/node_modules/t3/dist/bin.mjs service update

Environment

  • t3: 0.0.39-nightly.20260903.1268, and 0.0.37-nightly.20260829.1219 before the update
  • npm: 12.0.1
  • Node.js: v22.22.3
  • Operating system: Fedora Linux 44 (Server Edition), kernel 7.1.9-200.fc44.x86_64
  • Install type: systemd user service, headless, bound to a Tailnet address

Related: #7475, #9380, #6012.

Diagnosed by Claude Opus 5 via Claude Code.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions