Apt upgrade to crystal1.12 failed on ubuntu 22.04

My nightly Ubuntu upgrades failed and apt ended up in a somewhat broken state due to the crystal1.12 upgrade (if I recall correctly, this also happened between 1.10 and 1.11, but I’m not 100% sure).

The culprit seems to be:

dpkg: error processing archive /var/cache/apt/archives/crystal1.12_1.12.0-1+2.1_amd64.deb (--unpack):
 trying to overwrite '/usr/bin/crystal', which is also in package crystal1.11 1.11.2-1+1.1

The apt-get update and upgrade:

$ apt-get update
..
Get:7 http://download.opensuse.org/repositories/devel:/languages:/crystal/xUbuntu_22.04  InRelease [1,544 B]
..
Fetched 237 kB in 1s (222 kB/s)
Reading package lists... Done

$ apt-get dist-upgrade
Reading package lists...
Building dependency tree...
Reading state information...
Calculating upgrade...
The following package was automatically installed and is no longer required:
  crystal1.11
Use 'apt autoremove' to remove it.
The following NEW packages will be installed:
  crystal1.12
The following packages will be upgraded:
  crystal
1 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 34.7 MB of archives.
After this operation, 136 MB of additional disk space will be used.
Get:1 http://download.opensuse.org/repositories/devel:/languages:/crystal/xUbuntu_22.04  crystal 1.12.0-1+1.1 [1,088 B]
Get:2 http://download.opensuse.org/repositories/devel:/languages:/crystal/xUbuntu_22.04  crystal1.12 1.12.0-1+2.1 [34.7 MB]
debconf: unable to initialize frontend: Dialog
debconf: (TERM is not set, so the dialog frontend is not usable.)
debconf: falling back to frontend: Readline
debconf: unable to initialize frontend: Readline
debconf: (This frontend requires a controlling tty.)
debconf: falling back to frontend: Teletype
dpkg-preconfigure: unable to re-open stdin:
Fetched 34.7 MB in 1s (29.9 MB/s)
[615B blob data]
Preparing to unpack .../crystal_1.12.0-1+1.1_all.deb ...
Unpacking crystal (1.12.0-1+1.1) over (1.11.0-1+1.1) ...
Selecting previously unselected package crystal1.12.
Preparing to unpack .../crystal1.12_1.12.0-1+2.1_amd64.deb ...
Unpacking crystal1.12 (1.12.0-1+2.1) ...
dpkg: error processing archive /var/cache/apt/archives/crystal1.12_1.12.0-1+2.1_amd64.deb (--unpack):
 trying to overwrite '/usr/bin/crystal', which is also in package crystal1.11 1.11.2-1+1.1
dpkg-deb: error: paste subprocess was killed by signal (Broken pipe)
Errors were encountered while processing:
 /var/cache/apt/archives/crystal1.12_1.12.0-1+2.1_amd64.deb
needrestart is being skipped since dpkg has failed
E: Sub-process /usr/bin/dpkg returned an error code (1)

A couple of different commands that didn’t work out:

$ apt-get upgrade
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
You might want to run 'apt --fix-broken install' to correct these.
The following packages have unmet dependencies:
 crystal : Depends: crystal1.12 but it is not installed
E: Unmet dependencies. Try 'apt --fix-broken install' with no packages (or specify a solution).

$ apt --fix-broken install
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Correcting dependencies... Done
The following package was automatically installed and is no longer required:
  crystal1.11
Use 'apt autoremove' to remove it.
The following additional packages will be installed:
  crystal1.12
The following NEW packages will be installed:
  crystal1.12
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
1 not fully installed or removed.
Need to get 0 B/34.7 MB of archives.
After this operation, 136 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
(Reading database ... 147898 files and directories currently installed.)
Preparing to unpack .../crystal1.12_1.12.0-1+2.1_amd64.deb ...
Unpacking crystal1.12 (1.12.0-1+2.1) ...
dpkg: error processing archive /var/cache/apt/archives/crystal1.12_1.12.0-1+2.1_amd64.deb (--unpack):
 trying to overwrite '/usr/bin/crystal', which is also in package crystal1.11 1.11.2-1+1.1
dpkg-deb: error: paste subprocess was killed by signal (Broken pipe)
Errors were encountered while processing:
 /var/cache/apt/archives/crystal1.12_1.12.0-1+2.1_amd64.deb
needrestart is being skipped since dpkg has failed
E: Sub-process /usr/bin/dpkg returned an error code (1)

$ apt-get remove --purge crystal1.11
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
You might want to run 'apt --fix-broken install' to correct these.
The following packages have unmet dependencies:
 crystal : Depends: crystal1.12 but it is not going to be installed
E: Unmet dependencies. Try 'apt --fix-broken install' with no packages (or specify a solution).

Removing both crystal and crystal1.11 and then a reinstall did the trick:

$ apt-get remove --purge crystal crystal1.11
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages were automatically installed and are no longer required:
  libpcre16-3 libpcre2-16-0 libpcre2-32-0 libpcre2-dev libpcre2-posix3 libpcre3-dev libpcre32-3 libpcrecpp0v5
Use 'apt autoremove' to remove them.
The following packages will be REMOVED:
  crystal* crystal1.11*
0 upgraded, 0 newly installed, 2 to remove and 0 not upgraded.
1 not fully installed or removed.
After this operation, 136 MB disk space will be freed.
Do you want to continue? [Y/n] y
(Reading database ... 147898 files and directories currently installed.)
Removing crystal (1.12.0-1+1.1) ...
Removing crystal1.11 (1.11.2-1+1.1) ...
Processing triggers for man-db (2.10.2-1) ...
Scanning processes...
Scanning linux images...
..

$ apt-get install crystal
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  crystal1.12
The following NEW packages will be installed:
  crystal crystal1.12
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/34.7 MB of archives.
After this operation, 136 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
(Reading database ... 146254 files and directories currently installed.)
Preparing to unpack .../crystal1.12_1.12.0-1+2.1_amd64.deb ...
Unpacking crystal1.12 (1.12.0-1+2.1) ...
Selecting previously unselected package crystal.
Preparing to unpack .../crystal_1.12.0-1+1.1_all.deb ...
Unpacking crystal (1.12.0-1+1.1) ...
Setting up crystal1.12 (1.12.0-1+2.1) ...
Setting up crystal (1.12.0-1+1.1) ...
Processing triggers for man-db (2.10.2-1) ...
Scanning processes...
Scanning linux images...
..

$ crystal --version
Crystal 1.12.0 [aee9ab69e] (2024-04-09)

LLVM: 15.0.7
Default target: x86_64-unknown-linux-gnu

Although not a major issue, it would be nice if these upgrades didn’t require manual intervention :slight_smile:

2 Likes

Hm, yeah this should work seamlessly.

If somebody wants to try this, the reproduction is simply: apt install crystal1.11; apt install crystal

Unfortunately, I’m not sure what else we can do.
The packages crystal1.11 and crystal1.12 are marked as conflicting via Conflicts: in the deb control file.
I also tried adding Replaces:, but that doesn’t seem to change anything.

As far as I understand the documentation, apt should not allow installing crystal1.12 when crystal1.11 is already installed. But apparently it doesn’t, for whatever reason. :person_shrugging:

Any help is appreciated.

Off the top of my head, when installing the crystal package it also installs crystal1.11 as dependency.
When upgrading crystal later on, the dependency is changed to crystal1.12 in the new version, but that does not (afair) uninstall/remove the existing crystal1.11 package, resulting in the conflict.

I’ll try and find some time in the next couple of days to dig into it :slight_smile:

Yes, crystal is an empty/virtual package that always has the latest version as dependency. That should be all good.

And it doesn’t matter if you have installed crystal or not. crystal1.11 and crystal1.12 should exclude each other, regardless of wether they’re installed explicitly or as dependency of crystal.

I think this could maybe be achieved by getting rid of the “crystal” meta package and having the other packages provide “crystal” as a virtual package:

Package: crystal1.12
Provides: crystal (= 1.12)
Conflicts: crystal

Package: crystal1.11
Provides: crystal (= 1.11)
Conflicts: crystal

optionally with “Replaces: crystal”.

1 Like

I also encountered this issue, thanks for sharing the solution!

Good idea.
An explicit upgrade from crystal1.11 to crystal1.12 seems to work fine when there’s no crystal package.

However, with no explicit crystal package, apt install crystal will install the package from the distro repository (in case of Debian 12, that’s Crystal 1.6).

If you want to try yourself, both packages but no crystal package are available in this test repository:
https://software.opensuse.org//download.html?project=home%3Astraight-shoota%3Abranches%3Adevel%3Alanguages%3Acrystal&package=crystal1.11

@deiv Do you have any idea?

APT pinning on the end user system would help, but it’s always a pain. Or you could rename everything to crystal-upstream.

Unfortunately I can’t easily try myself, as there are probably no packages for linux-arm64, so Mac users developing for Linux using Docker or UTM virtualization are out of luck, unless resorting to UTM/QEMU emulation (really slow).

This could also work:

apt list --all-versions crystal
apt install crystal=1.11

but I don’t know offhand what implications that may bring, e.g. whether APT would consider the package for upgrades.

apt list --all-versions crystal only prints the actual crystal package from the Debian stable repo.

I believe I found the culprit! :rocket:

The Provides: crystal field needs a version specification in order to match with Conflicts in the other packages.
So crystal1.12 now has Provides: crystal (=1.12) and crystal1.11 has Provides: crystal (1.11).
Then APT correctly identifies the conflict and automatically removes the other package.

You may need to pull the largest package updates to see the effect.

4 Likes

Yes, in this case, the Provides field should have a version.
Note that only “=” is allowed in the version clause.

All the examples use a blank after the “=”. Not sure if that’s significant. => Provides: crystal (= 1.12)

The only relation allowed in the version clause in the Conflicts field seems to be “<<” (earlier than) though. You propably don’t use that, and I think you shouldn’t.

1 Like

Yeah that’s just a typo in the comment here. It’s Provides: crystal (1.11) of course.

We actually have version restrictions such as Conflicts: crystal (<< 1.12). In the future we might be able to have packages of different releases co-exist.