do-release-upgrade to 26.04 Crashes in _addSecuritySources() (ExplodedDeb822SourceEntry)¶
The Problem¶
Running do-release-upgrade from 24.04 to 26.04.1 ("resolute") crashes partway through
with an unhandled Python exception:
The traceback points into aptsources/sourceslist.py, inside _addSecuritySources().
This is a bug in Ubuntu's own ubuntu-release-upgrader package, not anything host-specific
— it reproduced identically on 5 different VPS hosts (different providers, different ages,
different installed package sets) during a single fleet upgrade session on 2026-10-02.
This is a known, confirmed upstream bug: Launchpad #2125393.
Symptom / Where It Crashes¶
Running do-release-upgrade -f DistUpgradeViewNonInteractive (or the interactive form)
proceeds normally through repository updates, then dies while the upgrader is trying to
add/verify a security-pocket source entry. The crash is deterministic for a given
sources.list.d layout — it happens at the same point on retry until the underlying code
is patched.
A red herring to rule out first: if a third-party .sources file (Netdata's, for
example) happens to be nearby in the traceback or gets touched right before the crash,
it's tempting to assume that file is the trigger. On the host where this was first hit,
moving netdata.sources aside and retrying still crashed — the traceback simply moved to
the official ubuntu.sources entry instead. The third-party file was not the cause.
Root Cause¶
aptsources/sourceslist.py defines an ExplodedDeb822SourceEntry class (used for DEB822
.sources-format repo files, which 26.04 uses for the default Ubuntu repos). That class's
__slots__ does not include section, and its __init__ never sets self.section. Later,
_addSecuritySources() reads .section off every source entry it's processing — which
works fine for classic one-line .list entries but raises AttributeError the moment it
hits a ExplodedDeb822SourceEntry instance.
This is confirmed by the equivalent, already-correct pattern that exists elsewhere in the
same file for other source-entry classes, which do set self.section in __init__ —
ExplodedDeb822SourceEntry is simply missing the same line.
Fix¶
Patch /usr/lib/python3/dist-packages/aptsources/sourceslist.py on the host before
re-running the upgrade:
- Add
"section"toExplodedDeb822SourceEntry's__slots__. - In that class's
__init__, addself.section = parent.section.
Example patch, applied via a Python script that asserts the exact target string exists (and exists exactly once) before editing — never a blind sed:
import re
path = "/usr/lib/python3/dist-packages/aptsources/sourceslist.py"
with open(path) as f:
src = f.read()
old_slots = '__slots__ = ("section_entry",)' # illustrative — match the real line
assert src.count(old_slots) == 1, "anchor not found or not unique — do not patch blind"
src = src.replace(old_slots, old_slots.replace(")", ', "section")'))
# ...similarly anchor-and-replace __init__ to add self.section = parent.section
with open(path, "w") as f:
f.write(src)
Verify without guessing:
diff /usr/lib/python3/dist-packages/aptsources/sourceslist.py \
/root/sourceslist.py.orig-<date> # confirm the diff is exactly the two intended lines
python3 -c "import aptsources.sourceslist" # import sanity check — would raise on a syntax error
Then re-run do-release-upgrade. The upgrade proceeds past _addSecuritySources() with no
further crash.
Always back up the original file first (cp sourceslist.py sourceslist.py.orig-<date>)
before patching — this is a stdlib-adjacent distro-packaged file, not something under your
own version control.
Real-World Example: MajorsHouse Fleet (2026-10-02)¶
Hit twice on the first host (teelia) during a 24.04→26.04.1 fleet upgrade — once on the first attempt, and again after the netdata-repo red herring above was ruled out. Diagnosed via the Launchpad bug report, hand-patched, and verified via the assert-guarded replacement + diff + import-check sequence above. The same patch was then applied proactively (before starting the upgrade, not after hitting the crash) on the remaining 4 hosts (dcaprod, tttpod, majorlinux, majortoot) — zero crashes on any of them. All 5 hosts completed the upgrade to 26.04.1 successfully; the patched file was left in place (it's superseded cleanly whenever Canonical ships a real fix via package update).
Prevention¶
- Before any 24.04→26.04
do-release-upgraderun, check whether this Launchpad bug is still open and pre-patch if so — avoids the crash entirely instead of hitting it mid-run. - Don't chase red herrings in the traceback. If a third-party repo file is nearby, test by moving it aside — if the crash persists against a different (official) source entry, the file you moved was never the cause.
- Any hand-patch to a distro-packaged Python file needs: a pre-patch backup, an assert-guarded exact-string replacement (never a blind regex/sed against stdlib-adjacent code), a diff against the backup afterward, and an import sanity check before trusting it.
Related¶
- Ubuntu dist-upgrade Quarantines Third-Party Repos — a different problem from the same
do-release-upgradeprocess (repos silently disabled, not a crash), worth checking in the same upgrade session. - Ubuntu-2604-Fleet-Upgrade — the project this fix came out of.