Yank and deprecate
Two operations that sound similar and are not.
| Effect on resolution | Reversible | Deletes anything | |
|---|---|---|---|
| Yank | stops being chosen | yes | no |
| Deprecate | none | yes | no |
| Unpublish | version is gone | no | yes |
Yank a version nobody should get by accident: a bad build, a wrong commit, a release with a secret in it. Deprecate a version you would still rather people did not pick, but which works.
Neither deletes anything. unpublish, with its 72-hour window, remains the
only destructive operation.
Yank
A yanked version:
- is not deleted, and unyanking restores it;
- stays downloadable by exact version, so lockfiles that already pin it keep resolving and existing builds do not break;
- is flagged wherever the protocol has a place for the flag, and excluded where it does not;
- never answers as latest.
packr-cli yank cargo/serde@1.0.0 --reason "built from the wrong commit"
packr-cli unyank cargo/serde@1.0.0
Ecosystem-agnostic API:
POST /api/v1/admin/packages/yank
{"ecosystem":"cargo","name":"serde","version":"1.0.0","yanked":true,"reason":"…"}
Cargo also has native verbs, which the registry implements:
DELETE /cargo/api/v1/crates/{crate}/{version}/yank and PUT .../unyank.
How each ecosystem shows it
| Ecosystem | Representation |
|---|---|
| cargo | yanked: true in the sparse index |
| PyPI | PEP 592 data-yanked / "yanked" in the simple index |
| JVM | yanked on the index line |
| NuGet | listed: false — the protocol's own word for it |
| Go | absent from @v/list; .info, .mod and .zip keep serving so go.sum still verifies |
| Maven | absent from <versions> in maven-metadata.xml; the jar and pom keep serving |
| npm | excluded from latest resolution |
Go and Maven have no in-protocol yank concept, so absence from the listing is the representation. That is why the exact-pin routes deliberately keep working.
Deprecate
A deprecated version still resolves, still answers as latest if it is newest, and still installs. The only effect is that clients whose protocol has somewhere to put the message show it.
packr-cli deprecate pypi/widget@1.0.0 --message "use widget2"
packr-cli undeprecate pypi/widget@1.0.0
POST /api/v1/admin/packages/deprecate
{"ecosystem":"pypi","name":"widget","version":"1.0.0","message":"use widget2"}
An empty message clears the notice, matching npm deprecate "". A missing
message field is a 400 rather than a clear, so a malformed request cannot
silently undo a publisher's warning.
npm's own PUT /-/v1/deprecate still works, but only reaches npm packages.
Where it is rendered
| Ecosystem | Representation |
|---|---|
| npm | deprecated on the version, in the packument and the version manifest |
| NuGet | catalogEntry.deprecation, the protocol's own model |
| JVM | deprecated on the index line |
| cargo, PyPI, Maven, Go | not rendered |
The last row is deliberate. The cargo sparse index, PEP 503/691 and
maven-metadata.xml define no deprecation field, and Go expresses deprecation
as a // Deprecated: comment inside go.mod — which the registry must not
rewrite, because that changes the file's hash and breaks every go.sum that
already records it. Inventing a non-standard field those clients ignore would
look like support without being it. The notice is still stored and still
readable through the API for all seven.