61

I want to upgrade from Ubuntu 16.04.5 LTS to 18.04, so ran sudo do-release-upgrade. After downloading and extracting bionic.tar.gz I get:

Can not upgrade 

Your python3 install is corrupted. Please fix the '/usr/bin/python3'
symlink.

I saw How to fix "python installation is corrupted"? and so I did sudo ln -sf /usr/bin/python3.6 /usr/bin/python3 thinking that it would be a similar problem. But that didn't work (still same error message).

I have a few python versions:

$ ls /usr/lib | grep python
python2.7
python3
python3.5
python3.6

$ update-alternatives --display python3
python3 - auto mode
  link best version is /usr/bin/python3.6
  link currently points to /usr/bin/python3.6
  link python3 is /usr/bin/python3
/usr/bin/python3.5 - priority 1
/usr/bin/python3.6 - priority 2

How do I fix python3?

1
  • 1
    And what about reinstallation (as mentioned in accepted answer)?
    – Kulfy
    Commented Dec 23, 2018 at 18:21

8 Answers 8

81

I just ran into this problem on Pop!_OS 18.04, trying to upgrade to 18.10, and it turns out that the problem lay in the symlink for /usr/bin/python and not for /usr/bin/python3. I had had /usr/bin/python3.6 configured as an alternative for python (not python3), and when I changed this, then I could run do-release-upgrade as expected.

I wish the error message pointed to python and not python3.


Before, with the problem:

$ update-alternatives --display python
python - manual mode
  link best version is /usr/bin/python3.6
  link currently points to /usr/bin/python2.7
  link python is /usr/bin/python
/usr/bin/python2.7 - priority 1
/usr/bin/python3.6 - priority 2 

I fixed it this way:

$ sudo update-alternatives --remove-all python
$ sudo ln -sf /usr/bin/python2.7 /usr/bin/python

Also see this comment below which describes a more precise solution that also better explains what is going on and how to fix it.

11
  • 6
    Yes, I can confirm that the solution works, this should be accepted answer.
    – Sumit Jain
    Commented May 17, 2019 at 6:16
  • 6
    Opting for update-alternatives --remove-all python was definitely an unnecessary overkill: All you needed to do was using update-alternatives --config python to have python point to the latest python2.* (e.g. python2.7), then use update-alternatives --config python3 to have python3 point to specifically python3.6 — which is the default Python 3 version for 18.04.
    – KiriSakow
    Commented Jun 9, 2019 at 0:45
  • 3
    If you need to upgrade to python 3.7 in Ubuntu 18.04, don't do it systemwide — or you're bound to end up having nasty little problems systemwide with essential tools like gnome-terminal, update-manager, etc. Rather use virtual environments (documentation here and here)
    – KiriSakow
    Commented Jun 9, 2019 at 1:05
  • 1
    @KiriSakow: update-alternatives --config python3 does not work as python3 is not a valid "link group" in the alternatives system.
    – Daniel K.
    Commented Sep 2, 2019 at 19:23
  • 1
    This is what worked for me. I had both python and python3 poiting to python3.6. I had to point /usr/bin/python back to python2.6
    – LnxSlck
    Commented Sep 21, 2019 at 17:57
47

You need to use the default Python 3 version for 16.04. That's 3.5, not 3.6. So run:

sudo ln -sf /usr/bin/python3.5 /usr/bin/python3

If that doesn't work, try reinstalling the python3 package.

sudo apt-get install --reinstall python3

By the way, update-alternatives --display python3 should give you update-alternatives: error: no alternatives for python3. Different versions of Python are not alternatives in Ubuntu.

9
  • 1
    Unfortunately, it does not work. kempelen.dai.fmph.uniba.sk/python_headache.png The system is up to date, and I have reinstalled the python and python3 packages, still the same. It is unique to this machine, other similar machine upgraded fine.
    – Palo
    Commented May 12, 2020 at 17:15
  • 5
    @palo I'm thinking that the reinstall command I mentioned previously might not actually reinstall everything. Try sudo apt-get install --reinstall python3 python3-minimal python3.5 python3.5-minimal.
    – wjandrea
    Commented May 12, 2020 at 17:52
  • 6
    It could have something to do with software installed by my colleagues on this machine in some local folders. I see there is linux embedded for rpi, miniconda3 that includes python3.6, and /usr/local/python2.7. Still which python reports /usr/bin/python, but pip goes from /usr/local/bin/pip. Even after changing /etc/environment placing /usr/local/... at the very end of the PATH, still the same message. I noticed that pyversions -d reports: "/usr/bin/python does not match the python default version. It must be reset to point to python2.7". So I replaced the link /usr/bin/python to point...
    – Palo
    Commented May 13, 2020 at 11:34
  • 5
    ...directly to /usr/bin/python2.7 instead of /etc/alternatives/python, and suddenly pyversions -d was happy, and do-release-upgrade did not complain about python and started the upgrade process as expected! So the problem was probably only this indirect double-linked path from python to python2.7 through /etc/alternatives.
    – Palo
    Commented May 13, 2020 at 11:36
  • 1
    @Palo Ah so you found the same solution as the top-voted answer
    – wjandrea
    Commented May 13, 2020 at 21:50
25

None of the answers here seem to explain how you can get to the solution yourself, so I took on a journey, in my case inspecting do-release-upgrade in KDE Neon on Ubuntu 18.04 LTS.

First, I ran it with tracefile -w and discovered that the actual release-upgrade-scripts were downloaded into a /tmp/ubuntu-release-upgrader-xxxxxxxx directory.

Using grep in that directory, I found the error message in DistUpgradeController.py:

❯ grep --line-number --recursive --binary-files=without-match "python3 install is corrupted"
DistUpgradeController.py:426:                             _("Your python3 install is corrupted. "

So I inspected the surrounding code, which used the function _pythonSymlinkCheck, jumped to that and discovered the root of the problem: The script expected the symlink /usr/bin/python3 to resolve to exactly /usr/bin/<debian_default_python>:

binaries_and_dirnames = [("python3", "python3")]
for binary, dirname in binaries_and_dirnames:
    debian_defaults = '/usr/share/%s/debian_defaults' % dirname
    if os.path.exists(debian_defaults):
        config = SafeConfigParser()
        with open(debian_defaults) as f:
            config.readfp(f)
        try:
            expected_default = config.get('DEFAULT', 'default-version')
        except NoOptionError:
            logging.debug("no default version for %s found in '%s'" %
                          (binary, config))
            return False
        try:
            fs_default_version = os.readlink('/usr/bin/%s' % binary)
        except OSError as e:
            logging.error("os.readlink failed (%s)" % e)
            return False
        if not fs_default_version in (expected_default, os.path.join('/usr/bin', expected_default)):

As visible from the script, <debian_default_python> is the default-version key in the DEFAULT section from /usr/share/python3/debian_defaults:

❯ cat /usr/share/python3/debian_defaults
[DEFAULT]
# the default python3 version
default-version = python3.6

My link did point to /usr/bin/python3.6, but via an extra indirection from update-alternatives, which the script doesn't resolve:

❯ python
Python 3.6.9 (default, Jul 17 2020, 12:50:27)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.readlink("/usr/bin/python3")
'/etc/alternatives/python3'
>>> os.readlink("/etc/alternatives/python3")
'/usr/bin/python3.6'

So in the end I also resorted to the nuclear option, but now with full knowledge of what was going on :)

sudo ln -sf /usr/bin/python3.6 /usr/bin/python3
2
  • 2
    My goodness, error message could have been better. Thousands of hours must have been wasted for all. It is not a problem of corruption, it is differnet version. People would only think of reinstalling by that word. Commented Oct 9, 2021 at 10:50
  • 1
    It looks like this part of the script has been fixed now cause it uses os.path.realpath(), which resolves a symbolic link recursively, unlike os.readlink(), which only resolves the first link in a chain.
    – wjandrea
    Commented Aug 18, 2022 at 18:31
17

I observed this error message on Windows 10 1903 running WSL Ubuntu when I wanted to upgrade from 16.04 LTS to 18.04 LTS.

After do-release-upgrade had failed, I switched python alternatives to every choice offered by update-alternatives --config python and ran the upgrade command again. That did not help.

Then I checked the log file /var/log/dist-upgrade/main.log which contained the lines

2019-09-02 20:58:08,686 DEBUG _pythonSymlinkCheck run
2019-09-02 20:58:08,687 DEBUG python symlink points to: '/etc/alternatives/python', but expected is 'python2.7' or
'/usr/bin/python2.7'
2019-09-02 20:58:08,688 ERROR pythonSymlinkCheck() failed, aborting

So although the error message mentions python3, the issue is about python2.

The upgrade script checks for /usr/bin/python linking to /usr/bin/python2, see the source code of DistUpgrade/DistUpgradeController.py here: ubuntu launchpad

So one solution is to completely remove python from the alternative system and add the link manually, as described in the most popular answer.

If you don't want to remove python from the alternative system, just change the link only for the time during the upgrade process:

# rm /usr/bin/python 
# ln -sf /usr/bin/python2.7 /usr/bin/python
# do-release-upgrade

This worked for me.

During the upgrade process, the link is automatically repaired. So when the upgrade is finished, it points to the python entry in the alternatives directory:

$ ls -l /usr/bin/python
lrwxrwxrwx 1 root root 24 Sep  2 22:01 /usr/bin/python -> /etc/alternatives/python

Edit: for thorough information, the issue might also appear if you upgrade from 18.04 LTS to 19.04 and the anwser applies to this situation, too.

2
  • 2
    Note: This answer also applies to an upgrade from Ubuntu 18.04 LTS to 19.04. I tried it myself after the update to 18.04 had finished successfully.
    – Daniel K.
    Commented Sep 5, 2019 at 8:27
  • This worked for me. The symlinks in /usr/bin/python and /usr/bin/python3 must be absolute: tail /var/log/dist-upgrade/main.log revealed 2021-10-07 14:34:42,156 DEBUG python symlink points to: './python2.7', but expected is 'python2.7' or '/usr/bin/python2.7'. You need all three python links intact and absolute: /usr/bin/python /usr/bin/python2 /usr/bin/python3. Commented Oct 7, 2021 at 13:38
6

Basically the solution to this problem consists of making /usr/bin/python point to the right version of Python your Ubuntu release expects (for instance, in 16.04 was Python2.7 and in 18.04 was Python3.6).

If you have several versions of Python installed in your system, you might be using update-alternatives to manage them. It doesn't matter much your default alternative for Python is the right version your system expects (3.6 in Ubuntu 18.04), it won't work.

The reason why this doesn't work is that, when using update-alternatives, /usr/bin/python3 points to /etc/alternatives/python3, and it seems that's not exactly the same as making /usr/bin/python3 point to /usr/bin/python3.6.

That's why the solution to this problem often consists of stop managing your Python3 versions with update-alternatives and make /usr/bin/python3 point to the right version of Python3 your system expects.

3
  • /usr/bin/python doesn't exist on a clean install of 18.04, but it does if you do an upgrade instead of a clean install or install the python package, in which case it should be Python 2.7, not 3.6. See PEP 394.
    – wjandrea
    Commented Oct 25, 2019 at 21:52
  • 2
    To be clear, different versions of Python are not alternatives on Ubuntu and should not be managed with update-alternatives. This is because the OS relies on a certain version being installed.
    – wjandrea
    Commented Oct 25, 2019 at 21:56
  • It would be nice if the error message reported what the actual error is - python not being set correctly instead of python3 ... Commented Jan 7, 2021 at 3:33
2

The following commands should work:

sudo update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.5 2
sudo rm /usr/bin/python
sudo ln -s /usr/bin/python2.7 /usr/bin/python
sudo do-release-upgrade
2

I just tried upgrading to jammy (22.04) and hit the same error. The error comes down to an incorrect symlink check in the upgrader package. I've submitted a bug report with a fix in here.

What you can do to work around the problem is have your python3 link directly to the final executable (without the detour via /etc/alternatives/python3):

sudo ln -s /usr/bin/python3.9 /usr/bin/python3
1

Here is the fix when I tried to upgrade my xenial 16.04 box to 18.04

mkdir /usr/share/python2/
cp /usr/share/python/debian_defaults /usr/share/python2/debian_defaults
cd /usr/bin/python2 /usr/bin/python.27

otherwise, the ubuntu-release-upgrader will complain with messages like

/usr/lib/python3$ sudo do-release-upgrade 
Checking for a new Ubuntu release
Get:1 Upgrade tool signature [819 B]                                                                                                                                                                               
Get:2 Upgrade tool [1,245 kB]                                                                                                                                                                                      
Fetched 1,245 kB in 0s (0 B/s)                                                                                                                                                                                     
authenticate 'bionic.tar.gz' against 'bionic.tar.gz.gpg' 
extracting 'bionic.tar.gz'

Reading cache

Checking package manager

Can not upgrade 

Your python3 install is corrupted. Please fix the '/usr/bin/python3' 
symlink. 

The major log file is located at

/var/log/dist-upgrade/main.log

and there the release updater complained. Also, the other file you may want to check out is actually in /tmp/ubuntu-release-upgrader/*

less /tmp/ubuntu-release-upgrader/*/DistUpgradeController.py

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .