crates.io doesn’t actually have a "yank" or "delete" button for releases, which is a problem when you push a broken version.
Here’s how to handle it:
The Problem: A Broken Release
You just pushed a new version of your crate to crates.io, let’s say my_crate v0.2.1. Turns out, it has a critical bug that breaks builds for everyone who upgrades. You need to stop people from using it immediately, but crates.io doesn’t let you delete releases.
The Solution: Releasing a New Version
The only way to "remove" a broken release is to publish a newer version that supersedes it. This doesn’t delete the bad release, but it makes it impossible for Cargo to select it by default.
Step-by-Step
-
Identify the Broken Version: You know you accidentally published
my_crate v0.2.1and it’s broken. -
Fix the Bug: Go to your crate’s source code and fix the bug that caused the breakage in
v0.2.1. -
Increment the Version: This is the crucial step. You must increment the version number. You cannot publish another
v0.2.1. The simplest and most common approach is to increment the patch version.- If your broken version was
0.2.1, your new version will be0.2.2. - If your broken version was
1.0.0, your new version will be1.0.1. - If your broken version was
0.1.0, your new version will be0.1.1.
Edit your
Cargo.tomlfile:[package] name = "my_crate" version = "0.2.2" # Changed from 0.2.1 edition = "2021" # ... other metadata - If your broken version was
-
Build and Publish the New Version: Now, build and publish this new version.
cargo build cargo publishCargo will upload
my_crate v0.2.2.
How This Works
When a user runs cargo build or cargo update, Cargo consults crates.io for the latest available versions of dependencies. If you published v0.2.2 after v0.2.1, Cargo’s default behavior is to select the highest version that satisfies the version constraints in their Cargo.toml.
If their Cargo.toml specifies my_crate = "0.2.1", Cargo will now pick 0.2.2 because it’s the latest compatible version. If their Cargo.toml specifies my_crate = "0.2", Cargo will also pick 0.2.2.
This effectively makes v0.2.1 unreachable by default. Users would have to explicitly tell Cargo to use v0.2.1 (which is rarely done and requires specific Cargo command-line flags or Cargo.lock manipulation), and even then, they’d see warnings that a newer version is available.
What About Explicit Version Pinning?
If a user has pinned the exact version my_crate = "0.2.1" in their Cargo.toml, and they run cargo update -p my_crate, Cargo will still try to update to 0.2.2 if the Cargo.toml allows it (e.g., my_crate = "0.2" or my_crate = "0.2.x"). If they have my_crate = "=0.2.1", Cargo will not automatically update. They would need to manually change their Cargo.toml to my_crate = "=0.2.2" and then run cargo update.
The key is that cargo publish is idempotent for a given version. You can’t publish 0.2.1 twice. The only way to "undo" a bad release is to publish a better one.
Communicating the Fix
It’s good practice to communicate this situation. You can:
- Create a new release on GitHub/GitLab: Announce that
v0.2.2is out and fixes critical issues from the previous release. - Update your crate’s README: Add a note about the problematic version and the fix.
The Next Hurdle
If you forget to increment the version number and try to publish the same version again, you’ll hit an error: error: failed to publish package 'my_crate' version '0.2.1'.