From 66c5cecb21828bc4d7ee9661fa7565eb86a2bdfe Mon Sep 17 00:00:00 2001 From: umeshmore45 Date: Thu, 19 Feb 2026 12:50:14 +0530 Subject: [PATCH 1/4] fix: improve unknown config warning with .npmrc section hint Fixes #8153 When npm warns about unknown user/project/env config keys, the message now includes a hint about using [section] syntax in .npmrc for package-specific config (e.g. electron_mirror, sass_binary_site). The hint is omitted for --cli flags since they are unrelated to .npmrc. --- docs/lib/content/configuring-npm/npmrc.md | 46 +++++++++++++++++++ .../test/lib/commands/config.js.test.cjs | 2 +- test/lib/commands/publish.js | 2 +- test/lib/commands/unpublish.js | 2 +- workspaces/config/lib/index.js | 7 ++- workspaces/config/test/index.js | 30 ++++++------ 6 files changed, 69 insertions(+), 20 deletions(-) diff --git a/docs/lib/content/configuring-npm/npmrc.md b/docs/lib/content/configuring-npm/npmrc.md index ee80908341aba..a9b2936ed65ed 100644 --- a/docs/lib/content/configuring-npm/npmrc.md +++ b/docs/lib/content/configuring-npm/npmrc.md @@ -124,6 +124,52 @@ _authToken=MYTOKEN //somewhere-else.com/another/:_authToken=MYTOKEN2 ``` +### Custom / third-party config keys + +npm only recognizes its own [configuration options](/using-npm/config). +If your `.npmrc` contains keys that are not part of npm's config definitions +(for example, `electron_mirror` or `sass_binary_site`), npm will emit a +warning: + +``` +warn Unknown user config "electron_mirror". +This will stop working in the next major version of npm. +``` + +These keys were historically tolerated but are not officially supported. +A future major version of npm will treat unknown top-level keys as errors. + +#### Using scoped sections in `.npmrc` + +Some tools (such as `@electron/get` or `node-sass`) read their own +configuration from environment variables or from `.npmrc` by convention. +To keep those values in your `.npmrc` without triggering npm warnings, +place them under an ini-style **section header**: + +```ini +; Before (triggers warning in npm >= 11.2.0) +electron_mirror=https://npmmirror.com/mirrors/electron/ +electron_custom_dir={{ version }} + +; After (no warning) +[electron] +mirror=https://npmmirror.com/mirrors/electron/ +custom_dir={{ version }} +``` + +Section headers are ignored by npm's config loader, so they will not +cause warnings. Whether the consuming tool reads from sections depends +on that tool — check its documentation. You can also set the values as +environment variables instead: + +```bash +export ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/" +export ELECTRON_CUSTOM_DIR="{{ version }}" +``` + +Environment variables are the most portable approach and work regardless +of `.npmrc` format. + ### See also * [npm folders](/configuring-npm/folders) diff --git a/tap-snapshots/test/lib/commands/config.js.test.cjs b/tap-snapshots/test/lib/commands/config.js.test.cjs index 5cb8fe9d0a094..0c23017ce2513 100644 --- a/tap-snapshots/test/lib/commands/config.js.test.cjs +++ b/tap-snapshots/test/lib/commands/config.js.test.cjs @@ -451,6 +451,6 @@ registry = "https://some.registry" exports[`test/lib/commands/config.js TAP config list with publishConfig local > warns about unknown config 1`] = ` Array [ - "Unknown publishConfig config /"other/". This will stop working in the next major version of npm.", + "Unknown publishConfig config /"other/". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See \`npm help npmrc\`.", ] ` diff --git a/test/lib/commands/publish.js b/test/lib/commands/publish.js index e444121b77e11..dba1851a261d8 100644 --- a/test/lib/commands/publish.js +++ b/test/lib/commands/publish.js @@ -55,7 +55,7 @@ t.test('respects publishConfig.registry, runs appropriate scripts', async t => { t.equal(fs.existsSync(path.join(prefix, 'scripts-prepublish')), false, 'did not run prepublish') t.equal(fs.existsSync(path.join(prefix, 'scripts-publish')), true, 'ran publish') t.equal(fs.existsSync(path.join(prefix, 'scripts-postpublish')), true, 'ran postpublish') - t.same(logs.warn, ['Unknown publishConfig config "other". This will stop working in the next major version of npm.']) + t.same(logs.warn, ['Unknown publishConfig config "other". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.']) }) t.test('re-loads publishConfig.registry if added during script process', async t => { diff --git a/test/lib/commands/unpublish.js b/test/lib/commands/unpublish.js index 996edf2b881fc..ca523a09fa9cb 100644 --- a/test/lib/commands/unpublish.js +++ b/test/lib/commands/unpublish.js @@ -409,7 +409,7 @@ t.test('publishConfig no spec', async t => { t.equal(joinedOutput(), '- test-package') t.same(logs.warn, [ 'using --force Recommended protections disabled.', - 'Unknown publishConfig config "other". This will stop working in the next major version of npm.', + 'Unknown publishConfig config "other". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.', ]) }) diff --git a/workspaces/config/lib/index.js b/workspaces/config/lib/index.js index bcddfc3cc70ce..ca8d2fb179af9 100644 --- a/workspaces/config/lib/index.js +++ b/workspaces/config/lib/index.js @@ -608,13 +608,16 @@ class Config { if (internalEnv.includes(key)) { return } + const hint = where !== 'cli' + ? ' To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.' + : '' if (!key.includes(':')) { - this.queueWarning(key, `Unknown ${where} config "${where === 'cli' ? '--' : ''}${key}". This will stop working in the next major version of npm.`) + this.queueWarning(key, `Unknown ${where} config "${where === 'cli' ? '--' : ''}${key}". This will stop working in the next major version of npm.${hint}`) return } const baseKey = key.split(':').pop() if (!this.definitions[baseKey] && !this.nerfDarts.includes(baseKey)) { - this.queueWarning(baseKey, `Unknown ${where} config "${baseKey}" (${key}). This will stop working in the next major version of npm.`) + this.queueWarning(baseKey, `Unknown ${where} config "${baseKey}" (${key}). This will stop working in the next major version of npm.${hint}`) } } } diff --git a/workspaces/config/test/index.js b/workspaces/config/test/index.js index 09d27bf4f37c4..ff19dc425c6ba 100644 --- a/workspaces/config/test/index.js +++ b/workspaces/config/test/index.js @@ -381,8 +381,8 @@ loglevel = yolo // warn logs are emitted as a side effect of validate config.validate() t.strictSame(logs.filter(l => l[0] === 'warn'), [ - ['warn', 'Unknown builtin config "builtin-config". This will stop working in the next major version of npm.'], - ['warn', 'Unknown builtin config "foo". This will stop working in the next major version of npm.'], + ['warn', 'Unknown builtin config "builtin-config". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], + ['warn', 'Unknown builtin config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], ['warn', 'invalid config', 'registry="hello"', 'set in command line options'], ['warn', 'invalid config', 'Must be', 'full url with "http://"'], ['warn', 'invalid config', 'proxy="hello"', 'set in command line options'], @@ -399,13 +399,13 @@ loglevel = yolo ['warn', 'invalid config', 'prefix=true', 'set in command line options'], ['warn', 'invalid config', 'Must be', 'valid filesystem path'], ['warn', 'config', 'also', 'Please use --include=dev instead.'], - ['warn', 'Unknown env config "foo". This will stop working in the next major version of npm.'], - ['warn', 'Unknown project config "project-config". This will stop working in the next major version of npm.'], - ['warn', 'Unknown project config "foo". This will stop working in the next major version of npm.'], - ['warn', 'Unknown user config "user-config-from-builtin". This will stop working in the next major version of npm.'], - ['warn', 'Unknown user config "foo". This will stop working in the next major version of npm.'], - ['warn', 'Unknown global config "global-config". This will stop working in the next major version of npm.'], - ['warn', 'Unknown global config "foo". This will stop working in the next major version of npm.'], + ['warn', 'Unknown env config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], + ['warn', 'Unknown project config "project-config". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], + ['warn', 'Unknown project config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], + ['warn', 'Unknown user config "user-config-from-builtin". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], + ['warn', 'Unknown user config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], + ['warn', 'Unknown global config "global-config". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], + ['warn', 'Unknown global config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], ['warn', 'invalid config', 'loglevel="yolo"', `set in ${resolve(path, 'project/.npmrc')}`], ['warn', 'invalid config', 'Must be one of:', ['silent', 'error', 'warn', 'notice', 'http', 'info', 'verbose', 'silly'].join(', '), @@ -600,12 +600,12 @@ loglevel = yolo ['warn', 'invalid config', 'prefix=true', 'set in command line options'], ['warn', 'invalid config', 'Must be', 'valid filesystem path'], ['warn', 'config', 'also', 'Please use --include=dev instead.'], - ['warn', 'Unknown env config "foo". This will stop working in the next major version of npm.'], - ['warn', 'Unknown user config "default-user-config-in-home". This will stop working in the next major version of npm.'], - ['warn', 'Unknown user config "foo". This will stop working in the next major version of npm.'], - ['warn', 'Unknown global config "global-config". This will stop working in the next major version of npm.'], - ['warn', 'Unknown global config "foo". This will stop working in the next major version of npm.'], - ['warn', 'Unknown global config "asdf". This will stop working in the next major version of npm.'], + ['warn', 'Unknown env config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], + ['warn', 'Unknown user config "default-user-config-in-home". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], + ['warn', 'Unknown user config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], + ['warn', 'Unknown global config "global-config". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], + ['warn', 'Unknown global config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], + ['warn', 'Unknown global config "asdf". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], ]) logs.length = 0 }) From d925af917d8df11650cb0ff1833560e782dabf7f Mon Sep 17 00:00:00 2001 From: umeshmore45 Date: Fri, 20 Feb 2026 00:46:50 +0530 Subject: [PATCH 2/4] docs: remove ini section recommendation per maintainer feedback --- docs/lib/content/configuring-npm/npmrc.md | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/docs/lib/content/configuring-npm/npmrc.md b/docs/lib/content/configuring-npm/npmrc.md index a9b2936ed65ed..36866113fa8c7 100644 --- a/docs/lib/content/configuring-npm/npmrc.md +++ b/docs/lib/content/configuring-npm/npmrc.md @@ -139,28 +139,9 @@ This will stop working in the next major version of npm. These keys were historically tolerated but are not officially supported. A future major version of npm will treat unknown top-level keys as errors. -#### Using scoped sections in `.npmrc` - Some tools (such as `@electron/get` or `node-sass`) read their own configuration from environment variables or from `.npmrc` by convention. -To keep those values in your `.npmrc` without triggering npm warnings, -place them under an ini-style **section header**: - -```ini -; Before (triggers warning in npm >= 11.2.0) -electron_mirror=https://npmmirror.com/mirrors/electron/ -electron_custom_dir={{ version }} - -; After (no warning) -[electron] -mirror=https://npmmirror.com/mirrors/electron/ -custom_dir={{ version }} -``` - -Section headers are ignored by npm's config loader, so they will not -cause warnings. Whether the consuming tool reads from sections depends -on that tool — check its documentation. You can also set the values as -environment variables instead: +You can set these values as environment variables instead: ```bash export ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/" From 0d06c0bea4fb21a443775977cd882d01980c9587 Mon Sep 17 00:00:00 2001 From: umeshmore45 Date: Fri, 20 Feb 2026 00:57:40 +0530 Subject: [PATCH 3/4] docs: use npmjs.org example domain to avoid squatting risk --- docs/lib/content/configuring-npm/npmrc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/lib/content/configuring-npm/npmrc.md b/docs/lib/content/configuring-npm/npmrc.md index 36866113fa8c7..59528145e157d 100644 --- a/docs/lib/content/configuring-npm/npmrc.md +++ b/docs/lib/content/configuring-npm/npmrc.md @@ -144,7 +144,7 @@ configuration from environment variables or from `.npmrc` by convention. You can set these values as environment variables instead: ```bash -export ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/" +export ELECTRON_MIRROR="https://mirrorexample.npmjs.org/mirrors/electron/" export ELECTRON_CUSTOM_DIR="{{ version }}" ``` From f1144162265057a928cd263d7dfbf6e86c404587 Mon Sep 17 00:00:00 2001 From: umeshmore45 Date: Fri, 20 Feb 2026 01:19:54 +0530 Subject: [PATCH 4/4] fix: remove ini section hint from unknown config warning message --- .../test/lib/commands/config.js.test.cjs | 2 +- test/lib/commands/publish.js | 2 +- test/lib/commands/unpublish.js | 2 +- workspaces/config/lib/index.js | 2 +- workspaces/config/test/index.js | 30 +++++++++---------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tap-snapshots/test/lib/commands/config.js.test.cjs b/tap-snapshots/test/lib/commands/config.js.test.cjs index 0c23017ce2513..bae0cc8ede394 100644 --- a/tap-snapshots/test/lib/commands/config.js.test.cjs +++ b/tap-snapshots/test/lib/commands/config.js.test.cjs @@ -451,6 +451,6 @@ registry = "https://some.registry" exports[`test/lib/commands/config.js TAP config list with publishConfig local > warns about unknown config 1`] = ` Array [ - "Unknown publishConfig config /"other/". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See \`npm help npmrc\`.", + "Unknown publishConfig config /"other/". This will stop working in the next major version of npm. See \`npm help npmrc\` for supported config options.", ] ` diff --git a/test/lib/commands/publish.js b/test/lib/commands/publish.js index dba1851a261d8..4bba640b6d8a3 100644 --- a/test/lib/commands/publish.js +++ b/test/lib/commands/publish.js @@ -55,7 +55,7 @@ t.test('respects publishConfig.registry, runs appropriate scripts', async t => { t.equal(fs.existsSync(path.join(prefix, 'scripts-prepublish')), false, 'did not run prepublish') t.equal(fs.existsSync(path.join(prefix, 'scripts-publish')), true, 'ran publish') t.equal(fs.existsSync(path.join(prefix, 'scripts-postpublish')), true, 'ran postpublish') - t.same(logs.warn, ['Unknown publishConfig config "other". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.']) + t.same(logs.warn, ['Unknown publishConfig config "other". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.']) }) t.test('re-loads publishConfig.registry if added during script process', async t => { diff --git a/test/lib/commands/unpublish.js b/test/lib/commands/unpublish.js index ca523a09fa9cb..4c8bc5e058afa 100644 --- a/test/lib/commands/unpublish.js +++ b/test/lib/commands/unpublish.js @@ -409,7 +409,7 @@ t.test('publishConfig no spec', async t => { t.equal(joinedOutput(), '- test-package') t.same(logs.warn, [ 'using --force Recommended protections disabled.', - 'Unknown publishConfig config "other". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.', + 'Unknown publishConfig config "other". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.', ]) }) diff --git a/workspaces/config/lib/index.js b/workspaces/config/lib/index.js index ca8d2fb179af9..8520a02b6ed77 100644 --- a/workspaces/config/lib/index.js +++ b/workspaces/config/lib/index.js @@ -609,7 +609,7 @@ class Config { return } const hint = where !== 'cli' - ? ' To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.' + ? ' See `npm help npmrc` for supported config options.' : '' if (!key.includes(':')) { this.queueWarning(key, `Unknown ${where} config "${where === 'cli' ? '--' : ''}${key}". This will stop working in the next major version of npm.${hint}`) diff --git a/workspaces/config/test/index.js b/workspaces/config/test/index.js index ff19dc425c6ba..3c52042c286f6 100644 --- a/workspaces/config/test/index.js +++ b/workspaces/config/test/index.js @@ -381,8 +381,8 @@ loglevel = yolo // warn logs are emitted as a side effect of validate config.validate() t.strictSame(logs.filter(l => l[0] === 'warn'), [ - ['warn', 'Unknown builtin config "builtin-config". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], - ['warn', 'Unknown builtin config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], + ['warn', 'Unknown builtin config "builtin-config". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.'], + ['warn', 'Unknown builtin config "foo". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.'], ['warn', 'invalid config', 'registry="hello"', 'set in command line options'], ['warn', 'invalid config', 'Must be', 'full url with "http://"'], ['warn', 'invalid config', 'proxy="hello"', 'set in command line options'], @@ -399,13 +399,13 @@ loglevel = yolo ['warn', 'invalid config', 'prefix=true', 'set in command line options'], ['warn', 'invalid config', 'Must be', 'valid filesystem path'], ['warn', 'config', 'also', 'Please use --include=dev instead.'], - ['warn', 'Unknown env config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], - ['warn', 'Unknown project config "project-config". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], - ['warn', 'Unknown project config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], - ['warn', 'Unknown user config "user-config-from-builtin". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], - ['warn', 'Unknown user config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], - ['warn', 'Unknown global config "global-config". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], - ['warn', 'Unknown global config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], + ['warn', 'Unknown env config "foo". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.'], + ['warn', 'Unknown project config "project-config". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.'], + ['warn', 'Unknown project config "foo". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.'], + ['warn', 'Unknown user config "user-config-from-builtin". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.'], + ['warn', 'Unknown user config "foo". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.'], + ['warn', 'Unknown global config "global-config". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.'], + ['warn', 'Unknown global config "foo". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.'], ['warn', 'invalid config', 'loglevel="yolo"', `set in ${resolve(path, 'project/.npmrc')}`], ['warn', 'invalid config', 'Must be one of:', ['silent', 'error', 'warn', 'notice', 'http', 'info', 'verbose', 'silly'].join(', '), @@ -600,12 +600,12 @@ loglevel = yolo ['warn', 'invalid config', 'prefix=true', 'set in command line options'], ['warn', 'invalid config', 'Must be', 'valid filesystem path'], ['warn', 'config', 'also', 'Please use --include=dev instead.'], - ['warn', 'Unknown env config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], - ['warn', 'Unknown user config "default-user-config-in-home". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], - ['warn', 'Unknown user config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], - ['warn', 'Unknown global config "global-config". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], - ['warn', 'Unknown global config "foo". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], - ['warn', 'Unknown global config "asdf". This will stop working in the next major version of npm. To pass package-specific config, use a scoped [sectionName] in .npmrc. See `npm help npmrc`.'], + ['warn', 'Unknown env config "foo". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.'], + ['warn', 'Unknown user config "default-user-config-in-home". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.'], + ['warn', 'Unknown user config "foo". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.'], + ['warn', 'Unknown global config "global-config". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.'], + ['warn', 'Unknown global config "foo". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.'], + ['warn', 'Unknown global config "asdf". This will stop working in the next major version of npm. See `npm help npmrc` for supported config options.'], ]) logs.length = 0 })