by Alex Becker

(Almost) Never Delete a Release

It's something all developers dread: publishing a release of a package you maintain, only to realize the build is broken or there's a serious bug. Your first instinct might be to delete the release from PyPI, indeed, PyPI's interface makes it easy to do, and hundreds of developers have done so in 2019 alone. But—barring exceptional circumstances like the inclusion of malicious code or an install step that wipes the user's computer—you should resist the urge, lest you break your users' builds.

There is a growing trend among users, especially larger organizations, to make builds reproducible by "freezing" dependencies, pinning each one to a specific version with every change or deploy. When you delete a release, you break the build for any project that pins that release.

PyDist maintains a feed of deleted releases to keep track of this problem. Over 10,000 have been deleted in the past 6 months, which has prompted PyDist to mirror PyPI for its users.

What to Do After You Publish a Bad Release

If you published a release that pulls in malicious code, or that will cause immediate and irreversible damage, then by all means delete the release from PyPI (and get in contact with them to have the file actually deleted from their CDN and so they can contact mirrors like PyDist). Otherwise, the best course of action is to take the most recent "good" release and re-release it as a patch bump to the bad release. That way tools like pip will not install the bad release unless they have been specifically instructed to. At the same time, anyone who has pinned the bad release will still be able to install it successfully, and in all likelihood will soon upgrade to the "good" release the next time they freeze their dependencies.

Communication is also key after publishing a bad release. Open an issue on GitHub or your bug tracker of choice, and add a notice to the changelog that a release should not be used. If you have a mailing list, make an announcement there as well.

Absolutely do not delete a release with the intent to re-upload a fixed version! PyPI does not let you re-upload files with the same name, which has been a nasty surprise to many maintainers who've tried this route. Since the filename of a wheel determines how pip treats it, you can't get around this by renaming your artifacts before upload.

What to Do After Someone Deletes a Release You Depend On

First, let me emphasize what not to do: attack the maintainer on GitHub, Twitter or anywhere else. Remember that you've been using their work for free.

Your first priority should be to un-break your builds, which can usually be fixed by pinning to a previous release of the offending package in your requirements.txt, Pipfile or pyproject.toml. If many releases have been deleted or you end up with a dependency conflict, you might have to take more a more drastic measure: find a copy of the wheel in one of your machines' pip wheel cache (~/.cache/pip/wheels on unix) and install the file directly with pip install. This may not play nicely with your dependency management system, so you may need to temporarily bypass it.

After that you might want to contact the maintainer to find out what happened and suggest future alternatives to deleting a release—keeping in mind that they've probably just gotten a bunch of angry comments from other users. I've had positive interactions with maintainers on GitHub with comments like this:

First, thanks @<maintainer> for maintaining <package>. It's a great library which I have used in multiple projects over the past few years.

I do think deleting a release from PyPI is the wrong course of action here though. When you first realize that a release is broken, it can seem like a disaster. But many of the people installing your package don't use much of it, often only importing it indirectly as a dependency of some other package, and may not suffer from whatever is broken in the release. If they pin package versions (like most orgs trying to avoid breaking), deleting a release is guaranteed to break them.

IMO, the best course of action is to immediately re-release the prior version as a patch bump to the broken version. Then nobody who hasn't already installed the bad release will install it, and you can publish a fixed release at your leisure.

But at the end of the day, the maintainer might not agree, or it could happen to you with another package. If this happens repeatedly, you may want to start using a PyPI mirror. Naturally I suggest using PyDist, but there are also great self-hosted options like devpi.