Repository navigation
npx t3 service update fails with EALLOWSCRIPTS because npx exports npm_config_allow_scripts to the pinned runtime install #9398
Description
Activity
Correction to this issue. I reviewed the npm 12.0.1 source and ran test installs on the same machine.
-
Steps to reproduce. I corrected the steps in the issue body. The original step 2 failed in the same way as step 3. The commands
t3 service installandt3 service updateboth callreconcileService. That function callsensurePinnedRuntimeInstalledinapps/server/src/cloud/bootService.tsat line 599. The correct order is: (1) install the service withnpx t3@nightly service installwhile~/.npmrchas noallow-scriptskey; (2) addallow-scripts[]=node-ptyto~/.npmrc; (3) runnpx t3@nightly service update; (4) read the newest file in~/.npm/_logs/. -
A reproduction that does not need t3. Run
npm exec --yes -c 'npm install --prefix /tmp/x --no-fund --no-audit msgpackr-extract@3.0.4'. On npm 12.0.1 the command exits 1 withEALLOWSCRIPTSwhen~/.npmrcholds a non-emptyallow-scriptsvalue. The same command exits 0 when the inner shell first runsunset npm_config_allow_scripts. -
Precondition. The failure needs a non-empty
allow-scriptsvalue in a.npmrcfile. The file can be the user file, the global file, the builtin file, or the project file of the directory where npx runs. When no value is set, npm exports the variable as an empty string, and npm ignores emptynpm_config_*variables inloadEnvin@npmcli/config/lib/index.js. The workarounds in node-pty native build silently skipped by npm allow-scripts policy, crash-loops the Linux background service #7475 create this precondition. Every user who applied them hits this failure on the nextnpx t3 service update. -
The export is not specific to npx. npm exports every non-default config value to every child process that npm starts. The code is
@npmcli/config/lib/set-envs.js.npm exec,npx, andnpm runscripts all passnpm_config_allow_scriptsto the t3 command line interface (CLI). -
Correction to the suggested fix. npm matches the variable name without regard to case, with the pattern
/^npm_config_/i. The CLI must also handleNPM_CONFIG_ALLOW_SCRIPTS. The functionProcessRunner.runinapps/server/src/processRunner.tsmerges a suppliedenvoverprocess.env, because it setsextendEnvwhenenvis present. The CLI cannot delete a variable through that interface. The CLI can setnpm_config_allow_scriptsto an empty string instead. npm ignores an empty value. A test install withnpm_config_allow_scripts=exits 0. I withdraw the suggestion to remove everynpm_config_*variable. The CLI cannot tell a variable that npx exported from a variable that the user set on purpose, for exampleNPM_CONFIG_USERCONFIGornpm_config_registry. Remove only theallow_scriptsvariable. -
Versions and key forms. The files
lib/utils/resolve-allow-scripts.jsandlib/commands/install.jsare identical in npm 12.0.1 and npm 12.0.2. The formallow-scripts=pkgand the formallow-scripts[]=pkgboth load as theusersource. Neither form throws. A stagedpackage.jsonwithallowScriptsdoes not prevent the throw, because the check at line 116 runs before npm readspackage.jsonat line 132. Pull request (PR) fix(server): stop npm 12 silently skipping node-pty builds in the pinned runtime #9380 and this fix are complementary. The manifest grants the scripts, and the empty variable prevents the throw.
The central claim of this issue stands. The
usersource does not throwEALLOWSCRIPTS.-
- added a commit that references this issue
on Sep 11, 2026
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.