Environment
- Distribution: Linux Mint 21.3 (Virginia)
- Edition: Xfce (64-bit)
- mintupdate version: 5.9.7 (verified with
mintupdate --version)
- Kernel series: 5.15 LTS
Bug Description
When the user attempts to remove old kernels via the Update Manager's graphical interface (View → Linux Kernels) and the removal process is interrupted (e.g., by accidentally clicking "Refresh" while the operation is in progress), the interface continues to display many kernels as "Obsolete" even though they are no longer physically installed on the system. This incorrect state persists across reboots and kernel list refreshes.
Examples of affected kernel versions:
5.15.0-173, 5.15.0-171, 5.15.0-170, 5.15.0-168, 5.15.0-164, 5.15.0-163, 5.15.0-161, 5.15.0-160, 5.15.0-157, and others.
Steps to Reproduce
- Open Update Manager (
mintupdate).
- Navigate to View → Linux Kernels.
- In the list of installed kernels, select an older one (not the currently active kernel) and click Remove.
- While the removal process is running, click the Refresh button (or trigger another update/refresh).
- The removal is interrupted (partial removal or error).
- After the interruption, the Linux Kernels window still shows the removed kernel(s) as "Obsolete", and often also shows other previously removed kernels.
Actual Behavior
- The GUI lists many kernels with the "Obsolete" status, falsely implying that they are still physically installed.
- The list does not reflect the true state of the system (confirmed via
dpkg and filesystem checks below).
Expected Behavior
- After a kernel is successfully removed, it should disappear from the list (or at most appear as an "available for installation" candidate without the "Obsolete" label).
- The kernel list should always match the output of
dpkg --list | grep linux-image – only genuinely installed kernels should be shown as "Installed" or "Active".
Supporting Evidence
1. System tools confirm kernels are absent
$ dpkg --list | grep linux-image
ii linux-image-5.15.0-176-generic 5.15.0-176.186 amd64 Signed kernel image generic
ii linux-image-5.15.0-177-generic 5.15.0-177.188 amd64 Signed kernel image generic
Only two kernels are actually installed. The phantom kernels are not present in the package manager.
2. Direct python3-apt check
import apt
cache = apt.Cache()
pkg = cache.get('linux-image-5.15.0-171-generic')
print(pkg.is_installed) # -> False
The apt cache correctly reports that the phantom kernel is not installed.
3. Filesystem check
No leftover files from old kernels exist in /boot or /lib/modules:
/boot/vmlinuz-* and /boot/initrd.img-* → only 5.15.0-176 and 5.15.0-177
/lib/modules → only 5.15.0-176-generic and 5.15.0-177-generic
4. The data-generation script (checkKernels.py) produces correct output
When executed manually, it correctly marks phantom kernels as installed=0:
$ /usr/lib/linuxmint/mintUpdate/checkKernels.py | grep "5.15.0-171"
KERNEL###005.015.000.171.181###5.15.0-171###5.15.0-171.181###0###0###1###1###jammy-updates###60###-generic
This proves that the source data fed to the GUI is accurate – the kernel is correctly reported as not installed (installed=0).
5. Extensive troubleshooting (none effective)
All of the following steps were performed, yet the phantom entries remained:
sudo apt clean, autoremove, autoclean, dpkg --configure -a
- Removal of caches:
~/.cache/mintupdate, ~/.config/mintupdate, /var/cache/mintupdate, /var/lib/mintupdate
- Resetting dconf keys for mintupdate
- Complete purge and reinstall of the
mintupdate package
- Deletion and re-download of apt lists (
/var/lib/apt/lists/*)
- Reboots after each step
6. Integrity of the patched file
The following command shows only the lines that were added or modified by the fix:
$ grep -n -E "import subprocess|truly_installed|prefix.*linux-image|ver = pkg\[len|full_ver not in truly" /usr/lib/linuxmint/mintUpdate/kernelwindow.py
6:import subprocess
515: truly_installed = set()
516: prefix = "linux-image-"
521: if pkg.startswith(prefix) and pkg.endswith(suffix) and pkg != "linux-image-generic":
522: ver = pkg[len(prefix):-len(suffix)] if len(suffix) > 0 else pkg[len(prefix):]
523: truly_installed.add(ver + suffix)
525: truly_installed = None # fallback
551: if truly_installed is not None:
553: if full_ver not in truly_installed:
Root Cause Analysis
The issue lies in the GUI component, most likely in /usr/lib/linuxmint/mintUpdate/kernelwindow.py, specifically in the build_kernels_list method. Although the data source correctly supplies installed=0 for removed kernels, the GUI appears to override or ignore this flag, relying instead on its own internal cache or previously stored state. As a result, kernels that were once installed continue to be treated as "installed" and are displayed under the "Obsolete" category.
Suspicious area (lines ~560–570 in kernelwindow.py):
if installed:
self.installed_kernels.append((kernel_type, version))
if not used:
Gdk.threads_enter()
self.button_massremove.set_sensitive(True)
Gdk.threads_leave()
self.remove_kernels_listbox.append(MarkKernelRow(Kernel(version, kernel_type, origin, installed),
self.marked_kernels, version_id,
newest_supported_in_series))
The variable installed here may remain True for previously removed kernels because of incomplete reset of internal state after an interrupted operation.
Proposed Fix (tested on 21.3 Xfce, works with kernel updates and removal through GUI)
A direct dpkg verification is added right before the list of installed kernels is built. This ensures that even if internal state is stale, kernels not truly installed are never displayed. The fix uses the standard CONFIGURED_KERNEL_TYPE variable and string slicing for robustness, making it compatible with all kernel types.
Changes to /usr/lib/linuxmint/mintUpdate/kernelwindow.py:
- Add
import subprocess at the top of the file (if not already present).
- In
build_kernels_list, after self.installed_kernels = [], insert a block that builds a set truly_installed from dpkg --list.
- In the block that checks
if installed:, add a condition: if truly_installed is available and the current kernel version is not in it, force installed = False.
This minimal patch (only a few lines added) has been tested and stabilises the kernel list display. It preserves all original functionality, including the kernel removal button logic.
Diff for kernelwindow.py (Proposed Fix):
--- kernelwindow.py.orig
+++ kernelwindow.py
@@ ... @@
import re
+import subprocess
...
class KernelWindow(Gtk.Window):
...
def build_kernels_list(self, kernels):
...
self.installed_kernels = []
+ try:
+ dpkg_out = subprocess.check_output(["dpkg", "--list"], universal_newlines=True)
+ truly_installed = set()
+ prefix = "linux-image-"
+ suffix = CONFIGURED_KERNEL_TYPE
+ for l in dpkg_out.splitlines():
+ if l.startswith("ii") and "linux-image-" in l and "unsigned" not in l:
+ pkg = l.split()[1]
+ if pkg.startswith(prefix) and pkg.endswith(suffix) and pkg != "linux-image-generic":
+ ver = pkg[len(prefix):-len(suffix)] if len(suffix) > 0 else pkg[len(prefix):]
+ truly_installed.add(ver + suffix)
+ except Exception:
+ truly_installed = None
...
for kernel in kernel_list_prelim:
...
if installed:
+ if truly_installed is not None:
+ full_ver = version + kernel_type
+ if full_ver not in truly_installed:
+ installed = False
self.installed_kernels.append((kernel_type, version))
...
This fix has been successfully applied on the same system and completely eliminates the phantom kernel entries, with no side effects.
Additional Notes
- The bug is reproducible on a fresh Linux Mint 21.3 Xfce installation after deliberately interrupting kernel removal.
- The proposed fix has been tested for stability through multiple reboots and a kernel update (5.15.0-179). It does not affect the normal operation of the Update Manager, including the kernel removal button (which correctly becomes active when spare kernels are present).
- A final test with an actual kernel removal through the GUI (5.15.0-176) was completed successfully. The removal left the system with only the active and one spare kernel, and the interface correctly switched the "Remove Kernels" button to inactive state, proving that the fix fully respects the original protection logic.
- A temporary rollback to the original
kernelwindow.py from a 2024 snapshot was performed. SHA256 hashes confirmed the file was identical. The "generic" tab behaviour remained unchanged, confirming the fix does not alter the kernel type selection UI – it is governed by standard mintupdate logic (the allow-kernel-type-selection setting and the absence of other kernel flavours).
- A simulation using the original
checkKernels.py output from a 2024 snapshot was conducted. The patched filter correctly identified a kernel marked as installed=1 that was not present in the current dpkg list, confirming the fix reliably eliminates phantom entries inherited from prior interrupted removals.
- This behaviour was not observed in older Mint versions (e.g., 20.x), suggesting it is associated with the newer kernel window design and the
checkKernels.py helper.
Environment
mintupdate --version)Bug Description
When the user attempts to remove old kernels via the Update Manager's graphical interface (View → Linux Kernels) and the removal process is interrupted (e.g., by accidentally clicking "Refresh" while the operation is in progress), the interface continues to display many kernels as "Obsolete" even though they are no longer physically installed on the system. This incorrect state persists across reboots and kernel list refreshes.
Examples of affected kernel versions:
5.15.0-173, 5.15.0-171, 5.15.0-170, 5.15.0-168, 5.15.0-164, 5.15.0-163, 5.15.0-161, 5.15.0-160, 5.15.0-157, and others.
Steps to Reproduce
mintupdate).Actual Behavior
dpkgand filesystem checks below).Expected Behavior
dpkg --list | grep linux-image– only genuinely installed kernels should be shown as "Installed" or "Active".Supporting Evidence
1. System tools confirm kernels are absent
Only two kernels are actually installed. The phantom kernels are not present in the package manager.
2. Direct
python3-aptcheckThe apt cache correctly reports that the phantom kernel is not installed.
3. Filesystem check
No leftover files from old kernels exist in
/bootor/lib/modules:4. The data-generation script (
checkKernels.py) produces correct outputWhen executed manually, it correctly marks phantom kernels as
installed=0:This proves that the source data fed to the GUI is accurate – the kernel is correctly reported as not installed (
installed=0).5. Extensive troubleshooting (none effective)
All of the following steps were performed, yet the phantom entries remained:
sudo apt clean,autoremove,autoclean,dpkg --configure -a~/.cache/mintupdate,~/.config/mintupdate,/var/cache/mintupdate,/var/lib/mintupdatemintupdatepackage/var/lib/apt/lists/*)6. Integrity of the patched file
The following command shows only the lines that were added or modified by the fix:
Root Cause Analysis
The issue lies in the GUI component, most likely in
/usr/lib/linuxmint/mintUpdate/kernelwindow.py, specifically in thebuild_kernels_listmethod. Although the data source correctly suppliesinstalled=0for removed kernels, the GUI appears to override or ignore this flag, relying instead on its own internal cache or previously stored state. As a result, kernels that were once installed continue to be treated as "installed" and are displayed under the "Obsolete" category.Suspicious area (lines ~560–570 in
kernelwindow.py):The variable
installedhere may remainTruefor previously removed kernels because of incomplete reset of internal state after an interrupted operation.Proposed Fix (tested on 21.3 Xfce, works with kernel updates and removal through GUI)
A direct
dpkgverification is added right before the list of installed kernels is built. This ensures that even if internal state is stale, kernels not truly installed are never displayed. The fix uses the standardCONFIGURED_KERNEL_TYPEvariable and string slicing for robustness, making it compatible with all kernel types.Changes to
/usr/lib/linuxmint/mintUpdate/kernelwindow.py:import subprocessat the top of the file (if not already present).build_kernels_list, afterself.installed_kernels = [], insert a block that builds a settruly_installedfromdpkg --list.if installed:, add a condition: iftruly_installedis available and the current kernel version is not in it, forceinstalled = False.This minimal patch (only a few lines added) has been tested and stabilises the kernel list display. It preserves all original functionality, including the kernel removal button logic.
Diff for
kernelwindow.py(Proposed Fix):This fix has been successfully applied on the same system and completely eliminates the phantom kernel entries, with no side effects.
Additional Notes
kernelwindow.pyfrom a 2024 snapshot was performed. SHA256 hashes confirmed the file was identical. The "generic" tab behaviour remained unchanged, confirming the fix does not alter the kernel type selection UI – it is governed by standardmintupdatelogic (theallow-kernel-type-selectionsetting and the absence of other kernel flavours).checkKernels.pyoutput from a 2024 snapshot was conducted. The patched filter correctly identified a kernel marked asinstalled=1that was not present in the currentdpkglist, confirming the fix reliably eliminates phantom entries inherited from prior interrupted removals.checkKernels.pyhelper.