You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Setting allow-scripts in a user or local (non-project) .npmrc makes a project's own package.json script fail with:
npm error code EALLOWSCRIPTS
npm error --allow-scripts is not allowed in project-scoped installs.
Add the entries to the "allowScripts" field in package.json, or to .npmrc, instead.
This happens even though the user never passed --allow-scripts — the value lives in a persistent .npmrc exactly as npm config set allow-scripts=<pkg> --location=user writes it — and even when the script explicitly passes --ignore-scripts.
The project package.json in question contains scripts like:
"scripts": {
"inst": "npm ci --ignore-scripts",
"perf": "node tests/ensure-playwright.mjs"
}
Running npm ci --ignore-scriptsdirectly in the workspace: ✅ succeeds (no error).
Running npm run inst (which runs that exact same command): ❌ fails with EALLOWSCRIPTS.
Running npm run perf (which runs that exact same node … command, and that script internally spawns an npm install): ❌ fails with EALLOWSCRIPTS.
The only difference between the working and failing invocations is whether the npm install/npm ci process is reached through npm run-script. npm run exports the resolved npm config as npm_config_* environment variables for the lifecycle script's child process. Because the outer process read allow-scripts from a user/local .npmrc, the inner npm install/npm ci inherits npm_config_allow_scripts and reads it via its env source. resolveAllowScripts groups the cli and env sources together and rejects any policy from them in a project-scoped install, so the inner install aborts — even though the value originated in a .npmrc, not a command-line flag, and even though the inner install was told --ignore-scripts.
This is the same root cause as #9783 (git-dep preparation), just reached through a different "shell-out to an inner npm install" path: an ambient npm_config_allow_scripts from a persistent .npmrc is misclassified as a forbidden CLI/env policy.
Environment
npm: 12.0.2
node: v26.6.0
OS: Windows 11
allow-scripts entry in user .npmrc: ["opencode-ai"]
node executable: C:\nvm4w\nodejs\node.exe
npm local prefix = C:\Users\xxx\xxx\xxx
HOME = C:\Users\xxx
cwd = C:\Users\xxx\xxx\xxx (a real project workspace, not global context)
How the offending setting gets there
This is the documented, recommended workflow. Installing a global package with an install script prints:
npm warn allow-scripts <pkg>@x.y.z (postinstall: node install.cjs)
npm warn allow-scripts Run `npm install -g --allow-scripts=<pkg>` to allow
these scripts once, or `npm config set allow-scripts=<pkg> --location=user`
to allow them for all global installs.
Following the second suggestion writes allow-scripts=<pkg> to the user.npmrc. From then on, npm run in any project on the machine that triggers an inner npm install fails — even ones that do not run any scripts and even ones that explicitly request --ignore-scripts.
Minimal, self-contained reproduction (no network / external repo required)
R=$(mktemp -d);cd"$R"# A user/local .npmrc with the entry exactly as# `npm config set allow-scripts=... --location=user` would write it.echo"allow-scripts=whatever">"$R/userrc"
mkdir app &&cd app
npm init -y >/dev/null
# A script that spawns an inner `npm install` (mirrors `npm ci` / ensure-playwright.mjs).
mkdir inner && (cd inner && npm init -y >/dev/null)
cat > package.json <<'EOF'{ "name": "app", "version": "1.0.0", "scripts": { "inst": "cd inner && npm install" } }EOF# (A) Direct inner install — works
(cd inner && npm install --userconfig "$R/userrc");echo"direct exit: $?"# (B) Same inner install, but reached through `npm run-script` — fails
npm run inst --userconfig "$R/userrc";echo"npm-run exit: $?"
Actual result (B)
npm error code EALLOWSCRIPTS
npm error --allow-scripts is not allowed in project-scoped installs.
Add the entries to the "allowScripts" field in package.json, or to .npmrc, instead.
Expected result
Both (A) and (B) complete. An allow-scripts value that lives in a persistent user/local .npmrc is, by definition, not a command-line flag. When a script is run inside a project (notably a script defined in that project's own package.json), npm should ignore non-project (user/local) .npmrcallow-scripts rather than forwarding it into the child npm install as a forbidden env-layer policy — and it must never abort a command that was explicitly told --ignore-scripts.
Notes on the trigger
The failure requires the inner process to be an npm install/npm ci reached through npm run-script (or any lifecycle script that shells out to npm). The reproduction above uses a trivial inner install with no scripts at all, proving the policy check itself — not any real script execution — is what trips.
It is independent of where the setting lives: reproduced identically with the entry in the user.npmrc and the global (etc/npmrc) file. There is no persistent-config location that both silences the global-install script warning and leaves npm run working.
It reproduces even when the outer/script command passes --ignore-scripts, because the EALLOWSCRIPTS throw at resolveAllowScripts happens purely from the presence of the env-layer policy, before --ignore-scripts is ever consulted.
Root cause (source pointers)
lib/utils/resolve-allow-scripts.js:107 throws EALLOWSCRIPTS when a policy is found in the cli/env sources and the install is not global and not skipProjectConfig. The grouping:
constcliPolicy=policyFromSources(npm,['cli','env'])...if(cliPolicy&&!npm.global&&!skipProjectConfig){throwObject.assign(newError('--allow-scripts is not allowed in project-scoped installs. '+'Add the entries to the "allowScripts" field in package.json, '+'or to .npmrc, instead.'),{code: 'EALLOWSCRIPTS'})}
npm run-script exports the resolved config into the child process's environment as npm_config_* variables (so lifecycle scripts can read e.g. process.env.npm_config_registry). A allow-scripts value sourced from a user/local .npmrc therefore arrives in the inner npm install as an env-layer value, which policyFromSources(npm, ['cli', 'env']) reads and resolveAllowScripts treats as a forbidden CLI flag.
This is the same defect described in #9783, where the ambient npm_config_allow_scripts instead arrives via the git-dep preparation inner install. The fix space is identical; npm run-script is simply an additional path that injects the env-layer value.
Suggested fixes
(Preferred) When npm run-script (and the git-dep preparation path from [BUG] A user/global .npmrcallow-scripts setting is forwarded to git-dependency preparation as an env-layer policy and fails the install with EALLOWSCRIPTS #9783) spawns an inner npm install, do not forward npm_config_allow_scripts from the ambient environment into the child. The inner install already receives a deliberately curated flag set, so script policy for the inner build should be passed explicitly (or omitted) rather than inherited ambiently. This leaves the cli/env grouping in resolveAllowScripts intact per RFC 868, while fixing the ambient-env inheritance that misclassifies a .npmrc value as a CLI policy.
Alternatively, in npm run-script, strip allow-scripts from the exported npm_config_* env when the script is project-scoped, so a user/local .npmrc policy is not re-applied to the project's own inner install.
At minimum, fix the error message: when the value came from a persistent .npmrc (directly or via npm_config_* env inheritance), do not tell the user to "add the entries to .npmrc" — that is where it already is, and the advice sends them in a circle. The message should also not fire when the offending command was invoked with --ignore-scripts.
Do not persist allow-scripts in a user/global .npmrc. Instead pass it only at the moment of the global install that needs it:
npm install -g <pkg> --allow-scripts=<pkg>
This approves the global install's script without leaving a persistent setting that later breaks npm run in unrelated projects. A project-scoped workaround is to move the policy into the project's own package.jsonallowScripts field (or project .npmrc) — but note that, per the linked #9783, the project-own-.npmrc path can still be hit via the env inheritance, so the robust fix is to avoid the ambient user/local entry entirely.
Summary
Setting
allow-scriptsin a user or local (non-project).npmrcmakes a project's ownpackage.jsonscript fail with:This happens even though the user never passed
--allow-scripts— the value lives in a persistent.npmrcexactly asnpm config set allow-scripts=<pkg> --location=userwrites it — and even when the script explicitly passes--ignore-scripts.The project
package.jsonin question contains scripts like:npm ci --ignore-scriptsdirectly in the workspace: ✅ succeeds (no error).npm run inst(which runs that exact same command): ❌ fails withEALLOWSCRIPTS.node tests/ensure-playwright.mjsdirectly: ✅ succeeds.npm run perf(which runs that exact samenode …command, and that script internally spawns annpm install): ❌ fails withEALLOWSCRIPTS.The only difference between the working and failing invocations is whether the
npm install/npm ciprocess is reached throughnpm run-script.npm runexports the resolved npm config asnpm_config_*environment variables for the lifecycle script's child process. Because the outer process readallow-scriptsfrom a user/local.npmrc, the innernpm install/npm ciinheritsnpm_config_allow_scriptsand reads it via itsenvsource.resolveAllowScriptsgroups thecliandenvsources together and rejects any policy from them in a project-scoped install, so the inner install aborts — even though the value originated in a.npmrc, not a command-line flag, and even though the inner install was told--ignore-scripts.This is the same root cause as #9783 (git-dep preparation), just reached through a different "shell-out to an inner npm install" path: an ambient
npm_config_allow_scriptsfrom a persistent.npmrcis misclassified as a forbidden CLI/envpolicy.Environment
12.0.2v26.6.0allow-scriptsentry in user.npmrc:["opencode-ai"]nodeexecutable:C:\nvm4w\nodejs\node.exenpm local prefix=C:\Users\xxx\xxx\xxxHOME=C:\Users\xxxcwd=C:\Users\xxx\xxx\xxx(a real project workspace, not global context)How the offending setting gets there
This is the documented, recommended workflow. Installing a global package with an install script prints:
Following the second suggestion writes
allow-scripts=<pkg>to the user.npmrc. From then on,npm runin any project on the machine that triggers an innernpm installfails — even ones that do not run any scripts and even ones that explicitly request--ignore-scripts.Minimal, self-contained reproduction (no network / external repo required)
Actual result (B)
Expected result
Both (A) and (B) complete. An
allow-scriptsvalue that lives in a persistent user/local.npmrcis, by definition, not a command-line flag. When a script is run inside a project (notably a script defined in that project's ownpackage.json), npm should ignore non-project (user/local).npmrcallow-scriptsrather than forwarding it into the childnpm installas a forbiddenenv-layer policy — and it must never abort a command that was explicitly told--ignore-scripts.Notes on the trigger
npm install/npm cireached throughnpm run-script(or any lifecycle script that shells out to npm). The reproduction above uses a trivial inner install with no scripts at all, proving the policy check itself — not any real script execution — is what trips..npmrcand the global (etc/npmrc) file. There is no persistent-config location that both silences the global-install script warning and leavesnpm runworking.--ignore-scripts, because theEALLOWSCRIPTSthrow atresolveAllowScriptshappens purely from the presence of theenv-layer policy, before--ignore-scriptsis ever consulted.Root cause (source pointers)
lib/utils/resolve-allow-scripts.js:107throwsEALLOWSCRIPTSwhen a policy is found in thecli/envsources and the install is not global and notskipProjectConfig. The grouping:npm run-scriptexports the resolved config into the child process's environment asnpm_config_*variables (so lifecycle scripts can read e.g.process.env.npm_config_registry). Aallow-scriptsvalue sourced from a user/local.npmrctherefore arrives in the innernpm installas anenv-layer value, whichpolicyFromSources(npm, ['cli', 'env'])reads andresolveAllowScriptstreats as a forbidden CLI flag.This is the same defect described in #9783, where the ambient
npm_config_allow_scriptsinstead arrives via the git-dep preparation inner install. The fix space is identical;npm run-scriptis simply an additional path that injects theenv-layer value.Suggested fixes
npm run-script(and the git-dep preparation path from [BUG] A user/global.npmrcallow-scriptssetting is forwarded to git-dependency preparation as an env-layer policy and fails the install withEALLOWSCRIPTS#9783) spawns an innernpm install, do not forwardnpm_config_allow_scriptsfrom the ambient environment into the child. The inner install already receives a deliberately curated flag set, so script policy for the inner build should be passed explicitly (or omitted) rather than inherited ambiently. This leaves thecli/envgrouping inresolveAllowScriptsintact per RFC 868, while fixing the ambient-env inheritance that misclassifies a.npmrcvalue as a CLI policy.npm run-script, stripallow-scriptsfrom the exportednpm_config_*env when the script is project-scoped, so a user/local.npmrcpolicy is not re-applied to the project's own inner install..npmrc(directly or vianpm_config_*env inheritance), do not tell the user to "add the entries to.npmrc" — that is where it already is, and the advice sends them in a circle. The message should also not fire when the offending command was invoked with--ignore-scripts.Related
.npmrcallow-scriptssetting is forwarded to git-dependency preparation as an env-layer policy and fails the install withEALLOWSCRIPTS#9783 — sameEALLOWSCRIPTSmisclassification, reached via the git-dependency preparation inner install. This issue is thenpm run-scriptsibling of that bug.Workaround (for anyone hitting this)
Do not persist
allow-scriptsin a user/global.npmrc. Instead pass it only at the moment of the global install that needs it:This approves the global install's script without leaving a persistent setting that later breaks
npm runin unrelated projects. A project-scoped workaround is to move the policy into the project's ownpackage.jsonallowScriptsfield (or project.npmrc) — but note that, per the linked #9783, the project-own-.npmrcpath can still be hit via the env inheritance, so the robust fix is to avoid the ambient user/local entry entirely.