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.
- Make sure that
~/.npmrc holds no allow-scripts key. - Install the background service with
npx t3@nightly service install. - Add
allow-scripts[]=node-pty to ~/.npmrc. - Run
npx t3@nightly service update. - 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.
What happened
npx t3@nightly service updatefails on Linux. The service stays on the old version.The command prints this error:
The error does not name the cause. The cause is in the npm debug log of the child install:
Note that argv holds no
--allow-scriptsflag.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 thenpm install --prefix <staging>child. npm 12 treats an environment variable as theenvsource. The functionresolveAllowScriptsinnpm/lib/utils/resolve-allow-scripts.jsthrowsEALLOWSCRIPTSwhen the policy comes from theclisource or theenvsource and the install is project-scoped.This command shows the leak:
Correction to PR #9380
PR #9380 says:
This is not correct. A user-level
~/.npmrcis theusersource.resolveAllowScriptsdoes not throw for theusersource. It throws only for theclisource and theenvsource. The user does not need to remove the key.I tested this on the machine that failed. I did not change
~/.npmrc. It still holdsallow-scripts[]=node-ptyandallow-scripts[]=msgpackr-extract. I started the same CLI without npx, so nonpm_config_allow_scriptsvariable existed:Result:
The install also compiled the native module, because the
~/.npmrcpolicy still applied as the.npmrclayer:The service now runs the new version and answers HTTP 200.
Steps to reproduce
Use a Linux machine with npm 12.
~/.npmrcholds noallow-scriptskey.npx t3@nightly service install.allow-scripts[]=node-ptyto~/.npmrc.npx t3@nightly service update.~/.npm/_logs/.The order is important.
service installandservice updateboth callensurePinnedRuntimeInstalled, so an install that starts after step 3 fails inthe same way.
This reproduction does not need t3:
The command exits 1 with
EALLOWSCRIPTSwhen~/.npmrcholds a non-emptyallow-scriptsvalue. The same command exits 0 when the inner shell first runsunset npm_config_allow_scripts.Suggested fix
Delete
npm_config_allow_scriptsfrom the environment of the childnpm installinensurePinnedRuntimeInstalled(apps/server/src/cloud/pinnedRuntime.ts). Delete everynpm_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.jsonmanifest, plus the user.npmrclayer.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:
Environment
Related: #7475, #9380, #6012.
Diagnosed by Claude Opus 5 via Claude Code.