nodejs/node · error · Error

invalid version range: ${spec}

Error message

invalid version range: ${spec}

What it means

`npm deprecate <pkg@range> <msg>` parses the spec and validates the range portion with semver.validRange. A dist-tag (e.g. 'latest') or malformed range fails this check and is rejected before any registry call.

Source

Thrown at deps/npm/lib/commands/deprecate.js:47

    return Object.keys(packages)
      .filter((name) =>
        packages[name] === 'write' &&
        (opts.conf.argv.remain.length === 0 ||
          name.startsWith(opts.conf.argv.remain[0])))
  }

  async exec ([pkg, msg]) {
    // msg == null because '' is a valid value, it indicates undeprecate
    if (!pkg || msg == null) {
      throw this.usageError()
    }

    // fetch the data and make sure it exists.
    const p = npa(pkg)
    const spec = p.rawSpec === '*' ? '*' : p.fetchSpec

    if (semver.validRange(spec, true) === null) {
      throw new Error(`invalid version range: ${spec}`)
    }

    const uri = '/' + p.escapedName
    const packument = await npmFetch.json(uri, {
      ...this.npm.flatOptions,
      spec: p,
      query: { write: true },
    })

    const versions = Object.keys(packument.versions)
      .filter(v => semver.satisfies(v, spec, { includePrerelease: true }))

    const dryRun = this.npm.config.get('dry-run')

    if (versions.length) {
      for (const v of versions) {
        packument.versions[v].deprecated = msg
        if (msg) {

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Provide a valid semver range, e.g. `npm deprecate pkg@'<2.0.0' 'msg'`
  2. Use '*' to deprecate every version: `npm deprecate pkg@'*' 'msg'`
  3. Pre-validate the range with require('semver').validRange(spec) in your script

Example fix

# before
npm deprecate mypkg@latest "broken in 1.x"

# after
npm deprecate mypkg@'1.x' "broken in 1.x"
Defensive patterns

Strategy: validation

Validate before calling

const semver = require('semver')
function resolveDeprecateRange(spec) {
  const p = require('npm-package-arg')(spec)
  const range = p.rawSpec === '*' ? '*' : p.fetchSpec
  if (semver.validRange(range, true) === null) {
    throw new Error(`Refusing to deprecate: '${range}' is not a valid semver range`)
  }
  return range
}

Type guard

function isValidDeprecateRange(spec) {
  const p = require('npm-package-arg')(spec)
  const range = p.rawSpec === '*' ? '*' : p.fetchSpec
  return semver.validRange(range, true) !== null
}

Prevention

When it happens

Trigger: Passing a dist-tag where a semver range is required (npm deprecate pkg@latest 'msg'), or a syntactically broken range like pkg@'>=1.<2'. Note '*' is allowed because the code special-cases rawSpec === '*' to '*'.

Common situations: Assuming deprecate accepts the same spec forms as install; copy-pasting a version expression with broken operators.

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/d2253bbdcf23e762. Report an issue: GitHub.