/errors/semver/typeerror-invalid-comparator
TypeError: Invalid comparator: latest (node-semver Range)
- tool
- SemVer
- exit code
- 1
- versions
- semver (npm) 7
- os
- any
TypeError: Invalid comparator: latest is thrown by the semver package (the one npm uses) when new semver.Range() meets a piece of the range string that is neither an operator nor a version. Each space-separated part of a range is a comparator (>=1.2.3, <2, ^1.4), and latest, foo or a lone - are not. Use semver.validRange() to check a string first; dist-tags like latest must be resolved to a version by the registry, not parsed as a range.
Reproduce it
npm init -y >/dev/null
npm install --silent --no-audit --no-fund semver@7 >/dev/null 2>&1
cat > ranges.js <<'EOF'
const semver = require("semver");
for (const r of ["^1.x", ">=1.2.3 <2", "latest", "1.2.3 - ", ">= 1.0.0 || foo"]) {
try {
console.log(JSON.stringify(r), "->", new semver.Range(r).range);
} catch (e) {
console.log(JSON.stringify(r), "->", `${e.name}: ${e.message}`);
}
}
console.log("validRange('latest'):", semver.validRange("latest"));
console.log("satisfies('1.2.3', 'latest'):", semver.satisfies("1.2.3", "latest"));
EOF
node ranges.jsOutput
"^1.x" -> >=1.0.0 <2.0.0-0
">=1.2.3 <2" -> >=1.2.3 <2.0.0-0
"latest" -> TypeError: Invalid comparator: latest
"1.2.3 - " -> TypeError: Invalid comparator: -
">= 1.0.0 || foo" -> TypeError: Invalid comparator: foo
validRange('latest'): null
satisfies('1.2.3', 'latest'): falseThe convenience functions (validRange, satisfies, maxSatisfying) catch the error and return null or false. Only the Range and Comparator constructors throw, so the error usually comes from your own code or from a tool that builds ranges directly.
Validate before building a Range
const semver = require("semver");
function parseRange(input) {
const r = semver.validRange(input);
if (r === null) throw new Error(`not a semver range: ${input}`);
return new semver.Range(r);
}In package.json, npm accepts a dist-tag ("react": "latest") as a dependency spec because npm resolves the tag through the registry before any semver range logic runs. Code that reads package.json and passes every value to semver.Range has to treat tags, git URLs, file: paths and aliases separately.