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
No backup dated today means no upgrade today. Treat that as a hard rule, not a suggestion. Whatever tool you use (I use restic to a local drive), verify the snapshot list actually shows today’s date before proceeding; a backup script that fails silently is worse than none, because you’ll only find out when you need it.
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. Remove out-of-tree DKMS modules
If you’ve ever installed a patched driver via DKMS (WiFi drivers are the classic case; mine was a MediaTek MT7925 stability series), deal with it now. A DKMS module written against older kernel APIs will try to rebuild against kernel 7.0 mid-upgrade and fail noisily, and in the worst case leaves the upgrade wedged.
dkms status # anything listed?
sudo dkms remove <module>/<version> --all
Check whether kernel 7.0 has absorbed whatever the module was patching before you reinstall anything; in my case the in-kernel driver had superseded the DKMS series entirely, so it never went back.
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.
If you don’t (I didn’t), the mitigation is that your old kernels stay in GRUB until you clean them up, so the worst realistic outcome is booting the previous kernel while you sort things out. That’s downtime, not data loss, and I accepted the risk; you should at least accept it consciously.
6. Check your PPAs serve the new release
Any PPA you depend on for a daily-driver app: check it publishes builds for the new release before you upgrade, not after your app breaks.
apt policy <package> # after pointing the PPA line at the new codename, or check the PPA page on Launchpad
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
For each repo, the question is whether its apt line carries the Ubuntu codename. Most vendor repos (1Password, Brave, Syncthing and friends) use a stable-style suite that doesn’t care what Ubuntu release you’re on; those just need re-enabling. Repos that embed the codename (PPAs, Tailscale’s Ubuntu repo) also need questing changed 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 on
apt updatemeans that repo doesn’t serve 26.04 yet. Re-disable it and retry in a few weeks; don’t leave apt erroring on every run. - 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.
One thing you do not need to do anything about: the initramfs generator. Fresh installs have defaulted to dracut since 25.10, but do-release-upgrade doesn’t switch existing systems; whichever generator you were on comes with you. My machine (upgraded release-over-release, so still on initramfs-tools) regenerated a bootable initrd without intervention, and dracut wasn’t even installed afterwards. dpkg -l initramfs-tools dracut tells you which side you’re on. Ignore guides telling you to migrate generators as part of the upgrade; initramfs-tools remains supported through 26.04’s life.
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
That cleared 195 obsolete packages for me. But here’s the gotcha my run surfaced: autoremove will not remove your old release’s kernel. When 25.10’s repos vanished from my sources, apt flipped the last 6.17 kernel’s status to manually-installed (it shows as local in apt list --installed), and autoremove never touches manual packages. If you want it gone, purge it explicitly:
dpkg -l | grep -E 'linux-(image|headers|modules|tools)-6\.' # see what's still there
sudo apt purge linux-image-6.17.0-40-generic linux-modules-6.17.0-40-generic \
linux-headers-6.17.0-40 linux-headers-6.17.0-40-generic \
linux-tools-6.17.0-40 linux-tools-6.17.0-40-generic
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.
Understand what you’re trading away: once the old kernels are purged, you have no fallback kernel. If a future kernel update won’t boot, your rescue path is a live USB and nothing else. Make the stick you didn’t make in preflight.
Finally, delete whatever pre-upgrade safety copies you made once the system has proven itself for a day or two. A backup you’ll never restore from is just clutter with sentimental value.
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.