nodejs/node · error · Error
Cannot implicitly apply the "latest" tag because previously
Error message
Cannot implicitly apply the "latest" tag because previously published version ${highestVersion} is higher than the new version ${manifest.version}. You must specify a tag using --tag. What it means
Thrown by `npm publish` when the new version is lower than or equal to the highest version already published (`semver.gte(highestVersion, manifest.version)`), the `tag` config is at its default (`latest`), and `--force` is not set. npm will not silently demote `latest` to an older release.
Source
Thrown at deps/npm/lib/commands/publish.js:180
const msg = `This command requires you to be logged in to ${outputRegistry}`
if (dryRun) {
log.warn(this.#command, `${msg} (dry-run)`)
} else {
throw Object.assign(new Error(msg), { code: 'ENEEDAUTH' })
}
}
if (!force) {
const { highestVersion, versions } = await this.#registryVersions(resolved, registry)
/* eslint-disable-next-line max-len */
const highestVersionIsGreater = !!highestVersion && semver.gte(highestVersion, manifest.version)
if (versions.includes(manifest.version)) {
throw new Error(`You cannot publish over the previously published versions: ${manifest.version}.`)
}
if (highestVersionIsGreater && isDefaultTag) {
throw new Error(`Cannot implicitly apply the "latest" tag because previously published version ${highestVersion} is higher than the new version ${manifest.version}. You must specify a tag using --tag.`)
}
}
const access = opts.access === null ? 'default' : opts.access
const verb = this.isStage ? 'Staging' : 'Publishing'
let msg = `${verb} to ${outputRegistry} with tag ${defaultTag} and ${access} access`
if (dryRun) {
msg = `${msg} (dry-run)`
}
log.notice('', msg)
let stageId
if (!dryRun) {
if (this.isStage) {
// Stage intentionally bypasses otplease — 2FA is deferred to approve/reject
const res = await libpub(manifest, tarballData, {
...opts,View on GitHub (pinned to 1b2de5e052)
Solutions
- Pass an explicit `--tag` (e.g. `--tag legacy` or `--tag lts`) so the older version gets its own dist-tag instead of `latest`.
- Set `"publishConfig": { "tag": "..." }` in package.json.
- Publish a version strictly greater than the current highest version.
- Use `--force` only if you knowingly want to move `latest` to an older version.
Example fix
// before npm publish // publishing 1.5.1 when 2.0.0 is latest // after npm publish --tag backport
Defensive patterns
Strategy: validation
Validate before calling
const semver = require('semver')
function chooseTag(newVersion, highestPublished, cliTag, publishConfigTag) {
const tag = cliTag || publishConfigTag || 'latest'
if (highestPublished && semver.gte(highestPublished, newVersion) && tag === 'latest') {
return 'backport' // or 'legacy', 'lts' — anything non-latest
}
return tag
} Prevention
- Maintain a documented dist-tag per release line (e.g. backport, lts).
- When publishing from a maintenance branch, default to a non-latest tag.
- Check `npm view <pkg> dist-tags` before publishing older versions.
When it happens
Trigger: Publishing a version where `highestVersion` from the registry `>=` `manifest.version`, while `isDefaultTag` is true (no `--tag`, no `publishConfig.tag`), without `--force`.
Common situations: Publishing a patch to an old release line (e.g. `1.2.x`) after `2.0.0` is already `latest`; downgrading; republishing after a hotfix branch merge into a lower minor.
Related errors
- You must specify a tag using --tag when publishing a prerele
- Tag name must not be a valid SemVer range: ${defaultTag.trim
- Tag name must not be a valid SemVer range: ${t}
- You cannot publish over the previously published versions: $
- `npm rebuild` only supports SemVer version/range specifiers
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/d5c385c067ad93a9.
Report an issue: GitHub.