{"record":{"id":"d2253bbdcf23e762","repo":"nodejs/node","slug":"invalid-version-range-spec","errorCode":null,"errorMessage":"invalid version range: ${spec}","messagePattern":"invalid version range: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"deps/npm/lib/commands/deprecate.js","lineNumber":47,"sourceCode":"    return Object.keys(packages)\n      .filter((name) =>\n        packages[name] === 'write' &&\n        (opts.conf.argv.remain.length === 0 ||\n          name.startsWith(opts.conf.argv.remain[0])))\n  }\n\n  async exec ([pkg, msg]) {\n    // msg == null because '' is a valid value, it indicates undeprecate\n    if (!pkg || msg == null) {\n      throw this.usageError()\n    }\n\n    // fetch the data and make sure it exists.\n    const p = npa(pkg)\n    const spec = p.rawSpec === '*' ? '*' : p.fetchSpec\n\n    if (semver.validRange(spec, true) === null) {\n      throw new Error(`invalid version range: ${spec}`)\n    }\n\n    const uri = '/' + p.escapedName\n    const packument = await npmFetch.json(uri, {\n      ...this.npm.flatOptions,\n      spec: p,\n      query: { write: true },\n    })\n\n    const versions = Object.keys(packument.versions)\n      .filter(v => semver.satisfies(v, spec, { includePrerelease: true }))\n\n    const dryRun = this.npm.config.get('dry-run')\n\n    if (versions.length) {\n      for (const v of versions) {\n        packument.versions[v].deprecated = msg\n        if (msg) {","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/npm/lib/commands/deprecate.js#L29-L65","documentation":"`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.","triggerScenarios":"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 '*'.","commonSituations":"Assuming deprecate accepts the same spec forms as install; copy-pasting a version expression with broken operators.","solutions":["Provide a valid semver range, e.g. `npm deprecate pkg@'<2.0.0' 'msg'`","Use '*' to deprecate every version: `npm deprecate pkg@'*' 'msg'`","Pre-validate the range with require('semver').validRange(spec) in your script"],"exampleFix":"# before\nnpm deprecate mypkg@latest \"broken in 1.x\"\n\n# after\nnpm deprecate mypkg@'1.x' \"broken in 1.x\"","handlingStrategy":"validation","validationCode":"const semver = require('semver')\nfunction resolveDeprecateRange(spec) {\n  const p = require('npm-package-arg')(spec)\n  const range = p.rawSpec === '*' ? '*' : p.fetchSpec\n  if (semver.validRange(range, true) === null) {\n    throw new Error(`Refusing to deprecate: '${range}' is not a valid semver range`)\n  }\n  return range\n}","typeGuard":"function isValidDeprecateRange(spec) {\n  const p = require('npm-package-arg')(spec)\n  const range = p.rawSpec === '*' ? '*' : p.fetchSpec\n  return semver.validRange(range, true) !== null\n}","tryCatchPattern":null,"preventionTips":["Pass an explicit semver range rather than a dist-tag","Pre-validate ranges with semver.validRange in release scripts","Use '*' only when you genuinely mean all versions"],"tags":["semver","deprecate","cli","registry"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}