Kubuntu 25.10 (questing) reached end of life on 9 July 2026, so the upgrade to 26.04 LTS (resolute) is now overdue whether you feel like it or not. I ran it in-place on my ThinkPad T14s in mid-July. The upgrade itself took about an hour and went clean, but only because the preflight caught two things that would have stopped it at step one, and the aftermath surfaced a handful of gotchas that nothing in the official release notes warns you about.
This guide is the whole path: preflight, upgrade, repo repair, verification, and cleanup, with the failures I hit written up so you can step around them. If you’re starting from a blank machine instead, see the fresh-install guide.
Contents
- Why bother
- Before you start
- The upgrade
- After: fix your third-party repos
- After: verify
- War story: AMD OpenCL broke
- War story: leave the BIOS clock alone
- Cleanup
Why bother
Two reasons, one of them compulsory:
- 25.10 support ended 9 July 2026. Interim releases get nine months; past that date, no security updates.
- 26.04 is an LTS and ships kernel 7.0, mesa 26, and Plasma’s current stack. Note the flavour fine print: the Ubuntu base gets Canonical’s five years (to April 2031), but Kubuntu’s own desktop packages get three years of flavour support (to April 2029). Either way you land on a base you won’t have to touch for years.
Before you start
The upgrade is a one-way door with a multi-gigabyte download and an hour of package churn in the middle. Every minute you spend here buys you a boring upgrade, which is the good kind.
1. Take a backup, and gate on it
Take a fresh backup before upgrading (I use restic to a local drive), and check that the run completed successfully and produced the expected snapshot. A same-day entry alone doesn’t prove the intended files were backed up. Personal-file backups protect your data; a system snapshot provides a separate rollback route, so check what each includes.
2. Power and connection
- Plug into AC and confirm it:
cat /sys/class/power_supply/AC*/onlineshould print1. - Run the upgrade from a local terminal session, not over SSH. If the network blips mid-upgrade over SSH, you’ve got a half-upgraded system and no console.
- You want a stable, unmetered connection; the download is several GB.
3. Check the release-upgrade prompt setting
This one would have stopped my run at step one. do-release-upgrade reads /etc/update-manager/release-upgrades, and if Prompt is set to never (which some minimal installs and past-you-being-clever configurations leave behind), it refuses outright with a message that doesn’t obviously point at the config file.
grep Prompt /etc/update-manager/release-upgrades
# want: Prompt=normal (or lts)
sudo sed -i 's/^Prompt=.*/Prompt=normal/' /etc/update-manager/release-upgrades
# confirm the upgrader now offers 26.04:
do-release-upgrade -c
4. Check out-of-tree DKMS modules
Check any DKMS drivers against the target kernel before upgrading:
dkms status
Compatible modules can stay. An obsolete module may fail to rebuild against the new kernel and interrupt package configuration; if you remove one, establish how the device will work without it and how to restore it if you abandon the upgrade.
My MediaTek MT7925 stability module was superseded by kernel 7.0’s in-kernel driver, so I removed it and never reinstalled it:
# Only for a module you've identified as obsolete or incompatible:
sudo dkms remove <module>/<version> --all
5. Rescue media reality check
Think through what happens if the machine doesn’t boot afterwards. My honest position going in: the 26.04 ISO I’d downloaded was sitting inside the LUKS-encrypted volume, which is exactly where you can’t reach it from a dead system. Write it to a USB stick if you have one around.
I proceeded without a stick, relying on the old kernels in GRUB as a fallback. An older kernel can help with a kernel regression, but it cannot undo upgraded userspace or repair every boot failure. Keep a known-working kernel and have external rescue media available; restoring a system snapshot and restoring personal files are separate recovery operations.
6. Check your PPAs serve the new release
For a daily-driver app supplied by a PPA, check the PPA’s published packages on Launchpad before upgrading. Leave the working source suite unchanged while checking. If the new release isn’t covered, decide whether to wait, use the distribution’s package or choose another maintained format such as an AppImage or Flatpak, checking version and feature differences.
The upgrade
Bring 25.10 fully current first, then hand over to the release upgrader:
sudo apt update && sudo apt full-upgrade
sudo do-release-upgrade
Budget about an hour plus a reboot. It’s interactive, so stay near the keyboard. What to expect:
- Third-party repos get disabled. This is automatic and expected; fixing them afterwards is its own section below.
- A “foreign packages” warning listing everything that didn’t come from Ubuntu’s own archive (PPA builds and the like). Continue; this is informational.
- Config-file conflict prompts. For each one, actually look at the diff rather than reflex-keeping either side. My only real one was
/etc/ssh/ssh_config, where the shipped default and my hardening disagreed on one directive; I kept the local version, and the upgrader saved the shipped copy alongside it asssh_config.dpkg-distfor later comparison. - An obsolete-packages removal offer (a couple of hundred packages, in my case 229). Decline it. It’s faster to review and remove them with
apt autoremoveafter you’ve confirmed the system is healthy, and declining keeps the upgrade’s failure surface smaller. - Desktop weirdness is possible mid-upgrade. My window manager crashed partway through, because the running compositor had its libraries swapped out from under it. This looks alarming and is benign; the desktop was fine after the post-upgrade reboot. Don’t interrupt the terminal doing the actual work.
Then it reboots into 26.04.
After: fix your third-party repos
The upgrader disables third-party sources two different ways, and you need to undo both:
Enabled: nolines inserted into your deb822.sourcesfiles- Renames of old-style list files:
whatever.listbecomeswhatever.list.disabled
Check each vendor’s instructions before re-enabling its repo. Repositories such as 1Password, Brave and Syncthing use stable-style suites that usually stay unchanged, though that alone doesn’t establish support for the new OS. For codename-dependent repositories, use the vendor’s supported suite; my PPA and Tailscale sources moved from questing to resolute.
# deb822 .sources files: delete the Enabled: no line
sudo sed -i '/^Enabled: no/d' /etc/apt/sources.list.d/<name>.sources
# codename-carrying repos: also swap the suite
sudo sed -i 's/^Suites: questing/Suites: resolute/' /etc/apt/sources.list.d/<ppa-name>.sources
# old-style .list.disabled files: recreate the .list with the new codename
# (or just rename back, for stable-suite repos), then remove the .disabled copy
sudo rm /etc/apt/sources.list.d/<name>.list.disabled
sudo apt update && sudo apt full-upgrade
Two things to watch:
- A 404 means the requested repository path is unavailable. Re-disable that source and check the vendor’s supported releases or alternative installation methods; a new suite may never be published. The installed app may still work, but its ongoing update route needs resolving. Don’t substitute an older suite without checking vendor guidance.
- The final
full-upgradematters. With the repos back, it pulls the packages the upgrade itself couldn’t resolve. Mine swapped in the current OpenCL stack and a newer darktable from its PPA in this pass.
The upgrader also leaves .save duplicates of your sources files lying around; they’re harmless and you can delete them whenever.
After: verify
uname -r # expect 7.0.x
lsb_release -d # expect Ubuntu 26.04 LTS
Then spot-check the things you actually rely on: your sync tools, your VPN, autostart apps, and anything GPU-accelerated (see the next section before you panic). If you removed a DKMS WiFi driver in preflight, confirm the in-kernel driver picked the device up: lsmod | grep <driver> and a working connection is the test.
My July upgrade retained initramfs-tools and generated a bootable initrd without intervention. That observation doesn’t establish what every upgrade will do: installed package names alone don’t identify which generator produced an image. Leave a working setup alone, and investigate any initrd-generation errors in the upgrade output before rebooting rather than adding a generator migration to the procedure.
War story: AMD OpenCL broke
My first post-upgrade spot-check failed: darktable, which leans on OpenCL for GPU acceleration, reported no usable device. This turned out to be three independent problems stacked on top of each other, which is worth knowing because fixing only one of them looks like the fix “didn’t work”.
1. mesa 26’s rusticl doesn’t expose AMD devices by default. The new OpenCL implementation ships with AMD support behind an environment variable. Persist it session-wide:
mkdir -p ~/.config/environment.d
echo 'RUSTICL_ENABLE=radeonsi' > ~/.config/environment.d/90-rusticl.conf
# takes effect at next login; verify afterwards with: env | grep RUSTICL
2. The OS was only seeing 512 MB of VRAM. OpenCL then refused the device with an “insufficient global memory” error. The BIOS setting for the integrated GPU’s memory allocation (UMA Frame Buffer Size, on this ThinkPad) displayed the right value, but re-entering the BIOS and re-saving the same setting restored the full allocation to the OS. I can’t explain the mechanism; I can tell you re-saving it worked, and that clinfo | grep -i global is how you check what the OS actually sees.
3. The application had blacklisted its own device. darktable had recorded the device as marked as disabled in its config during the broken era, so even with rusticl and VRAM fixed it still refused to use the GPU. Clearing the stale device entries from ~/.config/darktable/darktablerc and re-enabling OpenCL fixed the last leg. Other OpenCL applications keep equivalent per-device state; if the stack looks healthy but one app still refuses, go looking for where it cached the failure.
The general lesson: after a release upgrade, “GPU compute is broken” is rarely one problem. Work the stack in order (driver exposes device → device has resources → application accepts device) and verify each layer before moving up.
War story: leave the BIOS clock alone
After the upgrade I glanced at the BIOS clock, saw it was ten hours behind local time, and “fixed” it. Don’t do this. Linux stores hardware-clock time in UTC, so on any UTC+10 machine the BIOS clock is supposed to read ten hours behind; it looking wrong is it working. Setting it to local time made my login screen greet me at 07:13 in the evening until NTP sorted it out.
If your login screen shows a bizarre time after an upgrade, check whether someone (you) helpfully set the RTC to local time, and let NTP re-correct it rather than compounding the error.
Cleanup
Wait until the new kernel has survived a reboot and a separate cold boot (full power-off, not a restart). Those old kernels in GRUB are your no-USB rescue path; don’t remove them while 7.0 is still on probation. Then:
sudo apt autoremove --dry-run
# Review the proposed removals before running:
sudo apt autoremove
That cleared 195 obsolete packages for me, but left the last 6.17 kernel installed. It was marked manual; local in apt list --installed alone doesn’t establish that status or explain how it arose. Check manual status separately:
apt-mark showmanual 'linux-*'
dpkg -l | grep -E 'linux-(image|headers|modules|tools)-6\.'
Manual packages are excluded from autoremove. If you later purge obsolete kernel packages explicitly, use the versions actually installed and retain a known-working fallback image and its modules.
While you’re in there, dpkg -l | awk '$1=="rc"' | grep linux- will show residual config entries from every kernel you’ve ever removed; purging those is optional tidiness.
I purged the remaining old kernel, leaving no fallback at that point. I would retain a known-working kernel alongside rescue media for a future upgrade. Keep recovery copies until the system and the applications you rely on have proved themselves, then retire them under your normal backup retention policy.
That’s the whole path. The upgrade itself is genuinely routine in 2026; the failure modes live in the edges (preflight config, third-party repos, GPU stacks, and cleanup assumptions). If you’re setting up a machine from scratch instead, the Kubuntu + Claude Code setup guide covers that end to end.