Skip to content

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:

AttributeError: 'ExplodedDeb822SourceEntry' object has no attribute 'section'

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:

  1. Add "section" to ExplodedDeb822SourceEntry's __slots__.
  2. In that class's __init__, add self.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-upgrade run, 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.