The current state of package invalidation support across package managers
Tags: performance, opensource, productivity, todayilearned
Published: 2021-04-01 16:27:52

---
title: The current state of package invalidation support across package managers
published: true
description: Package invalidation (n): the indication that an open source maintainer doesn’t want you to use their package or release(s). Never heard of it? The process varies wildly across package managers.
tags: performance, opensource, productivity, todayilearned
---
<h3>Deprecate, retract, unpublish, abandon, yank, orphan, archive...</h3>
<p>What do all these have in common? Well, they’re different terms for what I’ll call “package invalidation.” Here’s what I mean by package invalidation:&nbsp;</p>
<p><span style="font-family: 'courier new', courier;">Package invalidation (n): the indication that an open source maintainer doesn’t want you to use their package or release(s).&nbsp;</span></p>
<h3>Do all package managers support invalidation?</h3>
<p>Some programming language ecosystems have built-in tooling for invalidation, and some purposely don’t allow it, but one thing certainly holds true: none are the same.&nbsp;</p>
<p>&nbsp;You can view package invalidation support in two dimensions:</p>
<ul>
<li aria-level="1"><strong>Package-level</strong> vs. r<strong>elease-level</strong>: either the full package is invalidated, or just specific releases (i.e. versions).</li>
<li aria-level="1"><strong>Deletion</strong> vs. <strong>deprecation</strong>: either the package is totally unavailable/gone/404’ed, or it is just marked as deprecated (i.e. a soft warning to not use the package).</li>
</ul>
<p>Note that “code deprecation” is a separate topic.&nbsp;</p>
<h3>Why would you invalidate a package?</h3>
<p>Maintainers will invalidate their packages for a range of reasons:</p>
<ul>
<li aria-level="1">the maintainers are <a href="https://blog.npmjs.org/post/141577284765/kik-left-pad-and-npm" rel="noopener" target="_blank">stepping away</a></li>
<li aria-level="1">it’s vulnerable to a bug or <a href="https://github.com/rubygems/rubygems.org/wiki/Gems-yanked-and-accounts-locked" rel="noopener" target="_blank">has malicious code</a></li>
<li aria-level="1">it’s being <a href="https://packagist.org/packages/guzzle/guzzle" rel="noopener" target="_blank">renamed or moved</a></li>
<li aria-level="1">there’s a <a href="https://hackage.haskell.org/package/http-enumerator" rel="noopener" target="_blank">better/faster alternative&nbsp;</a></li>
<li aria-level="1">secrets were <a href="https://github.com/clojars/clojars-web/issues/742" rel="noopener" target="_blank">accidentally published</a>&nbsp;</li>
<li aria-level="1">it has a <a href="https://github.com/mimemagicrb/mimemagic/issues/98" rel="noopener" target="_blank">licensing issue</a></li>
</ul>
<h3>Are there problems with package invalidation support?</h3>
<p>Yes 😬 ... package invalidation is a thorny and overlooked topic:</p>
<p>Firstly, <b>every ecosystem implements invalidation differently</b>. For example, the Maven package ecosystem for Java doesn’t allow removal of packages because it considers its package index immutable. Clojure, though—a language on the Java platform—follows suit but <a href="https://github.com/clojars/clojars-web/wiki/About#how-do-i-delete-a-jar" rel="noopener" target="_blank">will make exceptions for security’s sake</a> and is <a href="https://github.com/clojars/clojars-web/issues/766" rel="noopener" target="_blank">considering a more nuanced approach</a>. When you’re in a polyglot environment, recalling the differences among ecosystems will be arduous.</p>
<p>Another problem is that <b>it’s often difficult to know when a package/release that you use is invalidated</b>, unless it’s outright deleted (which might be too late for your CI builds). For example, even though RubyGems allows the removal of a specific release by the maintainer, you may never know if you are using cached versions of that release.</p>
<p>Lastly, a big problem we found is that <span style="font-weight: bold;">maintainers often don’t use the built-in tooling</span>. Sometimes package invalidation is just a note in the README (maybe a “DEPRECATED” note or a badge from <a href="http://unmaintained.tech/" rel="noopener" target="_blank">unmaintained.tech</a>). This makes it even trickier to be warned against using a package.</p>
<h3>Matrix of support</h3>
<p>Because this subject can be so complex and confusing, we have compiled a matrix of invalidation support for you to use as reference.&nbsp;</p>
<div data-hs-responsive-table="true" style="overflow-x: auto; max-width: 100%; margin-left: auto; margin-right: auto;">
<table style="border-style: solid; border-color: #2f3342; border-collapse: collapse;" border="1">
<tbody>
<tr>
<td style="background-color: #f5f3ef;">
<p><b>Language</b></p>
</td>
<td style="background-color: #f5f3ef; text-align: center;">
 <p><b>Package<br>index</b></p>
</td>
<td style="background-color: #f5f3ef; text-align: center;">
 <p><b>Package<br>deletion</b></p>
</td>
<td style="background-color: #f5f3ef; text-align: center;">
 <p><b>Release<br>deletion</b></p>
</td>
<td style="background-color: #f5f3ef; text-align: center;">
 <p><b>Package<br>deprecation</b></p>
</td>
<td style="background-color: #f5f3ef; text-align: center;">
 <p><b>Release<br>deprecation</b></p>
</td>
<td style="background-color: #f5f3ef; text-align: center;">
 <p><b>Terminology</b></p>
</td>
</tr>
<tr style="text-align: center;">
<td>
<p>Haskell&nbsp; </p>
</td>
<td>
<p><a href="https://hackage.haskell.org/">hackage.
<br>haskell.org</a></p>
</td>
<td>
<p>⛔️</p>
</td>
<td style="width: 62.6667px;">
<p>⛔️</p>
</td>
<td style="width: 89.3333px;">
<p>✅</p>
</td>
<td style="width: 89.3333px;">
<p>⛔️</p>
</td>
<td style="width: 122.667px;">
<p>“deprecate”</p>
</td>
</tr>
<tr style="text-align: center;">
<td style="width: 78.6667px;">
<p>Rust</p>
</td>
<td style="width: 178.667px;">
<p><a href="http://crates.io/">crates.io</a></p>
</td>
<td style="width: 68px;">
<p>⛔️</p>
</td>
<td style="width: 62.6667px;">
<p>⛔️</p>
</td>
<td style="width: 89.3333px;">
<p>⛔️</p>
</td>
<td style="width: 89.3333px;">
<p>✅</p>
</td>
<td style="width: 122.667px;">
<p>“yank”</p>
</td>
</tr>
<tr style="text-align: center;">
<td style="width: 78.6667px;">
<p><font-size="12px">Clojure</font></p>
</td>
<td style="width: 178.667px;">
<p><a href="http://clojars.org/">clojars.org</a> </p>
</td>
<td style="width: 68px;">
<p>⛔️</p>
</td>
<td style="width: 62.6667px;">
<p>✅</p>
</td>
<td style="width: 89.3333px;">
<p>⛔️</p>
</td>
<td style="width: 89.3333px;">
<p>⛔️ </p>
</td>
<td style="width: 122.667px;">
<p>“delete”</p>
</td>
</tr>
<tr style="text-align: center;">
<td style="width: 78.6667px;">
<p>Objective-C</p>
</td>
<td style="width: 178.667px;">
<p><a href="https://cocoapods.org/">cocoapods.org</a> </p>
</td>
<td style="width: 68px;">
<p>⛔️</p>
</td>
<td style="width: 62.6667px;">
<p>✅</p>
</td>
<td style="width: 89.3333px;">
<p>✅</p>
</td>
<td style="width: 89.3333px;">
<p>⛔️</p>
</td>
<td style="width: 122.667px;">
<p>“delete” & “deprecate”</p>
</td>
</tr>
<tr style="text-align: center;">
<td style="width: 78.6667px;">
<p>PHP</p>
</td>
<td style="width: 178.667px;">
<p><a href="http://packagist.org/">packagist.org</a> </p>
</td>
<td style="width: 68px;">
<p>✅ </p>
</td>
<td style="width: 62.6667px;">
<p>⛔ </p>
</td>
<td style="width: 89.3333px;">
<p>✅ </p>
</td>
<td style="width: 89.3333px;">
<p>⛔ </p>
</td>
<td style="width: 122.667px;">
<p>“delete“ &amp; “abandon” </p>
</td>
</tr>
<tr style="text-align: center;">
<td style="width: 78.6667px;">
<p>Python&nbsp; </p>
</td>
<td style="width: 178.667px;">
<p><a href="https://anaconda.org/">anaconda.org</a> </p>
</td>
<td style="width: 68px;">
<p>✅ </p>
</td>
<td style="width: 62.6667px;">
<p>✅ </p>
</td>
<td style="width: 89.3333px;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px;">
<p>⛔️ </p>
</td>
<td style="width: 122.667px;">
<p>“delete” </p>
</td>
</tr>
<tr style="text-align: center;">
<td style="width: 78.6667px;">
<p>Perl&nbsp; </p>
</td>
<td style="width: 178.667px;">
<p><a href="https://www.cpan.org/">www.cpan.org</a> </p>
</td>
<td style="width: 68px;">
<p>✅&nbsp; </p>
</td>
<td style="width: 62.6667px;">
<p>✅ </p>
</td>
<td style="width: 89.3333px;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px;">
<p>✅ </p>
</td>
<td style="width: 122.667px;">
<p>“delete” &amp;&nbsp; </p>
<p>“deprecate” </p>
</td>
</tr>
<tr style="text-align: center;">
<td style="width: 78.6667px;">
<p>Go&nbsp; </p>
</td>
<td style="width: 178.667px;">
<p><a href="https://pkg.go.dev/">pkg.go.dev</a> </p>
</td>
<td style="width: 68px;">
<p>⛔️ </p>
</td>
<td style="width: 62.6667px;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px;">
<p>✅&nbsp; </p>
</td>
<td style="width: 122.667px;">
<p>“retract” </p>
</td>
</tr>
<tr style="text-align: center;">
<td style="width: 78.6667px;">
<p>Java&nbsp; </p>
</td>
<td style="width: 178.667px;">
<p><a href="https://search.maven.org/">search.<br>maven.org</a>, etc </p>
</td>
<td style="width: 68px;">
<p>⛔️ </p>
</td>
<td style="width: 62.6667px;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px;">
<p>⛔️ </p>
</td>
<td style="width: 122.667px;">&nbsp;</td>
</tr>
<tr style="text-align: center;">
<td style="width: 78.6667px;">
<p>Erlang&nbsp; </p>
</td>
<td style="width: 178.667px;">
<p><a href="https://hex.pm/">hex.pm</a> </p>
</td>
<td style="width: 68px;">
<p>⛔️ </p>
</td>
<td style="width: 62.6667px;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px;">
<p>✅&nbsp; </p>
</td>
<td style="width: 122.667px;">
<p>“retire” </p>
</td>
</tr>
<tr style="text-align: center;">
<td style="width: 78.6667px;">
<p>JS&nbsp; </p>
</td>
<td style="width: 178.667px;">
<p><a href="https://www.npmjs.com/">www.npmjs.com</a> </p>
</td>
<td style="width: 68px;">
<p>✅&nbsp; </p>
</td>
<td style="width: 62.6667px;">
<p>✅&nbsp; </p>
</td>
<td style="width: 89.3333px;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px;">
<p>✅&nbsp; </p>
</td>
<td style="width: 122.667px;">
<p>“unpublish” &amp; “deprecate” </p>
</td>
</tr>
<tr style="text-align: center;">
<td style="width: 78.6667px;">
<p>.NET&nbsp; </p>
</td>
<td style="width: 178.667px;">
<p><a href="http://nuget.org/">nuget.org</a> </p>
</td>
<td style="width: 68px;">
<p>⛔️ </p>
</td>
<td style="width: 62.6667px;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px;">
<p>✅&nbsp; </p>
</td>
<td style="width: 122.667px;">
<p>“deprecate” </p>
</td>
</tr>
<tr style="text-align: center;">
<td style="width: 78.6667px;">
<p>Python&nbsp; </p>
</td>
<td style="width: 178.667px;">
<p><a href="http://pypi.org/">pypi.org</a> </p>
</td>
<td style="width: 68px;">
<p>✅ </p>
</td>
<td style="width: 62.6667px;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px;">
<p>✅&nbsp; </p>
</td>
<td style="width: 122.667px;">
<p>“delete” &amp; “yank” </p>
</td>
</tr>
<tr style="text-align: center;">
<td style="width: 78.6667px;">
<p>R&nbsp; </p>
</td>
<td style="width: 178.667px;">
<p><a href="http://cran.r-project.org/">cran.r-project.org</a> </p>
</td>
<td style="width: 68px;">
<p>✅&nbsp; </p>
</td>
<td style="width: 62.6667px;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px;">
<p>✅&nbsp; </p>
</td>
<td style="width: 89.3333px;">
<p>⛔️ </p>
</td>
<td style="width: 122.667px;">
<p>“archive” &amp; “orphan” </p>
</td>
</tr>
<tr style="text-align: center;">
<td style="width: 78.6667px;">
<p>Ruby </p>
</td>
<td style="width: 178.667px;">
<p><a href="http://rubygems.org/">rubygems.org</a> </p>
</td>
<td style="width: 68px;">
<p>⛔️ </p>
</td>
<td style="width: 62.6667px;">
<p>✅&nbsp; </p>
</td>
<td style="width: 89.3333px;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px;">
<p>⛔️ </p>
</td>
<td style="width: 122.667px;">
<p>“yank” </p>
</td>
</tr>
<tr>
<td style="text-align: center;">
<p>Swift </p>
</td>
<td style="width: 178.667px; text-align: center;">
<p><a href="http://swiftpackageregistry.com/">swiftpackage<br>
registry.com</a> </p>
</td>
<td style="width: 68px; text-align: center;">
<p>⛔️ </p>
</td>
<td style="width: 62.6667px; text-align: center;">
<p>⛔️ </p>
</td>
<td style="width: 89.3333px; text-align: center;">
<p>⛔️&nbsp; </p>
</td>
<td style="width: 89.3333px; text-align: center;">
<p>⛔️ </p>
</td>
<td style="width: 122.667px; text-align: center;">&nbsp;</td>
</tr>
</tbody>
</table>
</div>
<h3>Other questions to consider</h3>
<p>There are some other details that will determine how invalidation works, too. Can an invalidated package be aliased or redirected to another package? How are name handoffs or disputes handled? Can deleted releases be re-published?</p>
<h3>How the Tidelift Subscription can help</h3>
<p>It can be very tricky to learn about deprecated packages and to navigate each ecosystem’s support, even if you’re paying attention. So how would you be alerted to and/or act upon an invalidated package?</p>
<p>Tidelift catalogs can help: <a href="https://tidelift.com/catalogs">catalogs</a> <span>provide a birds-eye view of all the open source packages that your organization is using</span>. Catalogs have a “Releases are actively maintained” standard that you can enable and enforce.&nbsp;</p>
<p><img src="https://f.hubspotusercontent30.net/hubfs/4008838/maintenance-release-actively-maintained.png" alt="maintenance-release-actively-maintained" width="516" loading="lazy" style="width: 516px; margin-left: auto; margin-right: auto; display: block;">When enabled, it will let you know when a deprecated package is in use and lets you block it from all your projects. We pull this data via the official tooling from each ecosystem as best we can, so you don’t have to worry about all these details.</p>
<p>And by paying for the Tidelift Subscription, you’re also <a href="https://blog.tidelift.com/pay-the-maintainers" rel="noopener" target="_blank">paying the maintainers</a>. The maintainers know best whether a package has been invalidated, and we work closely with the maintainers to bring that information directly to you via the Tidelift Subscription. Curious how that works? You can <a href="https://tidelift.com/subscription/watch-demo" rel="noopener" target="_blank">watch a short demo</a>, or, better yet, <a href="https://tidelift.com/solutions/schedule-demo" rel="noopener" target="_blank">schedule a custom demo</a> and one of our team members will show you how Tidelift catalogs work.</p>