Fixing npm 'Cannot Publish Over Previously Published Version'
npm publish fails because the version already exists on the registry — npm forbids overwriting a published version. This page explains why immutability matters and how to publish correctly.
Exact symptoms and error messages
npm error code E403
npm error 403 Forbidden - PUT https://registry.npmjs.org/@acme%2fui
npm error You cannot publish over the previously published versions: 2.3.0.
Root cause analysis
Published versions are immutable by design: consumers and lockfiles pin exact versions, so allowing an overwrite would let a version's contents change under everyone who already installed it. The error means your package.json version was not bumped since the last publish. The fix is a new version, chosen by the semantic versioning rules, published through the lifecycle in npm Registry Publishing Workflows.
Published versions are immutable by design, and that immutability is a feature, not a limitation. Consumers pin exact versions in their lockfiles, and integrity hashes verify that the tarball for a version never changes. If the registry allowed republishing different contents under the same version, every install that had already resolved it would silently get different code — the exact reproducibility guarantee the whole system depends on. The 403 is the registry protecting that guarantee.
The error therefore means one concrete thing: your package.json version was not bumped since the last publish. The fix is never to force an overwrite — there is no such operation — but to choose a new version. Which part to bump follows from the change, per the semantic versioning rules: a fix is a patch, a compatible feature is a minor, a breaking change is a major.
Published versions are immutable by design, and that immutability is the reason the registry refuses to publish over an existing version. Consumers pin exact versions in their lockfiles, and integrity hashes verify that the tarball for a version never changes, so allowing an overwrite would let a version's contents change under everyone who already installed it — breaking the reproducibility the whole system depends on. The error means one concrete thing: your package.json version was not bumped since the last publish.
The situation usually arises from a manual publish where the version bump was forgotten, or from a CI pipeline that republishes without computing a new version. Because there is no overwrite operation — the registry has no way to replace a version's contents — the fix is never to force the publish but to choose a new version. Which part to bump follows from the change: a fix is a patch, a backward-compatible feature is a minor, a breaking change is a major.
Resolution and configuration patch
Bump to an unused version before publishing:
# choose the bump that matches the change
npm version patch # or minor / major
npm publish
If you must ship a fix to an already-published version, publish a new patch and, if the bad version is dangerous, deprecate it — you cannot overwrite it.
Bump to an unused version before publishing, and automate the bump so it cannot be forgotten:
# Choose the bump that matches the change
npm version patch # or minor / major
npm publish
# Confirm the local version is not already published
npm view your-pkg@$(node -p "require('./package.json').version") 2>&1 | grep -q E404 && echo free || echo taken
For a fix to an already-published version, publish a new patch — you cannot overwrite the old one. If the bad version is dangerous, deprecate it with a message pointing at the fix so installers are warned.
CLI validation and debug commands
# See which versions already exist
npm view @acme/ui versions --json
# Confirm your local version is unused
npm view @acme/ui@$(node -p "require('./package.json').version") 2>&1 | grep -q 'code E404' && echo 'free' || echo 'taken'
Prevention and CI guardrails
- Automate version bumping so a publish never reuses a version.
- Gate CI publishing on a changed version to fail fast on duplicates.
- Deprecate a bad version (
npm deprecate) instead of trying to overwrite it. - Use prerelease tags for iterative testing so you do not burn stable versions.
- Automate version bumping so a publish never reuses a version.
- Gate CI publishing on a changed version so a duplicate fails fast.
- Deprecate a bad version with
npm deprecateinstead of trying to overwrite it. - Use prerelease dist-tags for iterative testing so you do not burn stable versions.
Automating version bumps so this never recurs
The durable fix is to remove the manual step where a version can be forgotten. When versioning is derived automatically — from conventional commits or changeset intent files — a publish can never reuse a version, because the version is computed from the changes rather than typed by hand.
- run: npx changeset version # computes the next version from intent files
- run: npm publish
With Changesets or semantic-release driving the bump, the release pipeline reads the accumulated changes, calculates the correct next version, updates package.json, and publishes — with no opportunity for a human to publish twice from the same version. This turns 'cannot publish over existing version' from a recurring papercut into a class of error the pipeline makes structurally impossible, which is the point of automating the release.
Recovering from a bad published version
Because you cannot overwrite a version, recovering from a broken release means shipping a new one and steering consumers away from the old. Publish a fixed higher version immediately, then deprecate the broken one with a message that points at the fix.
# Ship the fix as a new version
npm version patch && npm publish
# Warn anyone installing the broken version
npm deprecate your-pkg@2.3.0 "Broken release — upgrade to 2.3.1"
npm deprecate does not remove the version — consumers who pinned it still resolve it — but it surfaces a warning on install that guides them to the fixed release. For a genuinely dangerous version there is a narrow, time-limited npm unpublish window with restrictions, but deprecation plus a prompt patch is the standard, non-disruptive recovery that respects the immutability every consumer relies on.
Recovering from a broken published version
Because you cannot overwrite a version, recovering from a broken release means shipping a new one and steering consumers away from the old. Publish a fixed higher version immediately, then deprecate the broken one with a message that names the replacement. npm deprecate your-pkg@2.3.0 "Broken release — upgrade to 2.3.1" attaches a warning that installers see without removing the version, so consumers who pinned it still resolve it but are guided to the fix. Deprecation turns a dead end into a signpost, which is far more useful than silence.
Unpublishing is the blunt, dangerous alternative, and the registry deliberately restricts it: only within a short window after publish, and never for a version others may already depend on, because removing a version breaks every lockfile that pinned it. For a genuinely dangerous version — one that leaks secrets or ships malware — the narrow unpublish window exists, but the standard, non-disruptive recovery is a prompt patch plus a deprecation. Treating the lifecycle as additive — ship forward, deprecate the old — respects the immutability every consumer relies on and keeps them moving with you across versions rather than stranded on a broken one.
Preventing version collisions with automated releases
The durable fix for the can't-publish-over-a-version error is to remove the manual step where a version can be reused. When the version is computed automatically — from conventional commits with semantic-release, or from changeset intent files with Changesets — a publish structurally cannot collide with an existing version, because the tool reads the accumulated changes, calculates the next version, and updates the manifest before publishing. There is no opportunity for a human to publish twice from the same version.
This is why an automated release pipeline treats the version as derived rather than typed. The pipeline reads the changes, computes the version, generates the changelog, publishes, and tags the commit, all without a hand-entered version number. Adding a lightweight guard — a CI check that the version to be published does not already exist on the registry — catches any edge case before the publish step, turning a would-be duplicate into an early, clear failure. Between deriving the version and guarding against collisions, the pipeline makes the immutable-version error a class of mistake that simply cannot reach the registry.
Using prerelease versions for iterative testing
One reason teams hit the can't-publish-over-a-version error is iterating on a release — publishing, finding a problem, and wanting to republish the same version with a fix. The clean way to iterate without burning stable versions is prerelease versions published under a dist-tag. A 2.1.0-rc.1, 2.1.0-rc.2, and so on can each be published and installed by opt-in consumers, so you can test a release candidate in the wild as many times as needed, each under a new prerelease number, before promoting the final stable version.
Prerelease identifiers sort below their stable counterpart, so a caret range like ^2.0.0 never resolves to a release candidate — only consumers who explicitly request the prerelease tag receive it. This means the iteration happens on versions that stable consumers never see, and promotion is a single npm dist-tag add pkg@2.1.0 latest once the candidate proves out. Using prerelease channels for iteration sidesteps the immutability constraint entirely: you never need to republish a version because each iteration gets its own prerelease number, and the stable version is published exactly once, when it is ready.
Frequently Asked Questions
Can I ever overwrite a published version?
No. Published versions are immutable. You can npm deprecate or, within a short window and with restrictions, npm unpublish, but you cannot republish different contents under the same version.
What if I published a broken version?
Publish a fixed higher version immediately, then deprecate the broken one with a message pointing to the fix so installers are warned.
Can I ever overwrite a published version?
No — published versions are immutable so that lockfiles and integrity hashes stay valid. You can deprecate a version or, within a narrow window, unpublish it, but you cannot republish different contents under the same version number.
How do I stop reusing a version by accident?
Automate the bump. With Changesets or semantic-release, the next version is computed from the changes, so a publish can never reuse a version — the manual step where it could be forgotten is removed.
What do I do about a broken release I already published?
Publish a fixed higher version immediately, then npm deprecate the broken one with a message pointing at the fix. Deprecation warns installers without removing the version, respecting the immutability consumers depend on.
Can I republish over an existing version to fix it?
No — published versions are immutable so lockfiles and integrity hashes stay valid. Publish a fixed higher version instead, and if the old one is broken, deprecate it with a message pointing at the fix. There is no overwrite, only a new release.
How do I stop reusing a version by accident?
Automate the bump so the version is computed from the changes rather than typed, and add a CI check that the target version does not already exist. With the version derived, a publish structurally cannot reuse a number.
What do I do about a broken version I already published?
Publish a fixed higher version immediately, then npm deprecate the broken one with a message pointing at the fix. Deprecation warns installers without removing the version, respecting the immutability consumers depend on.
How do I iterate on a release without republishing the same version?
Use prerelease versions under a dist-tag: 2.1.0-rc.1, 2.1.0-rc.2, and so on, each published and installable by opt-in consumers. Stable consumers never receive them, and you promote the final version once with npm dist-tag add, so you never need to republish a version.
Does --force let me publish over a version?
No. npm publish --force overrides some warnings but cannot overwrite an existing version — the registry rejects it regardless, because versions are immutable. The only path is a new version number.
Why does the registry forbid overwriting a version at all?
Because consumers pin exact versions in lockfiles and verify them with integrity hashes. If a version's contents could change, every install that already resolved it would silently get different code, breaking the reproducibility the whole ecosystem depends on. Immutability is a feature, not a limitation.
Can I unpublish and republish the same version?
Only within a narrow time window after the original publish, and never for a version others may depend on — unpublishing breaks every lockfile that pinned it. The safe path is a new version plus a deprecation of the old, not an unpublish-republish cycle.
Related
- npm Registry Publishing Workflows — the publish lifecycle behind this error.