Fixing Broken Dependencies and Held Packages on apt

Fixing Broken Dependencies and Held Packages on apt

What's the difference between held packages and broken dependencies?

Conclusion: They are different problems. Held means a package is intentionally excluded from upgrades - not an error. Broken dependencies means a required dependency cannot be satisfied, so installs or upgrades cannot complete. The first is handled with apt-mark, the second with apt --fix-broken install.

People tend to lump these two symptoms together as "a dependency problem", but the causes and fixes differ.

# (A) held: an update was simply kept back. Not an error.
$ sudo apt upgrade
The following packages have been kept back:
  linux-generic nvidia-driver-535
# (B) broken: a dependency cannot be satisfied and the operation stops. This is abnormal.
$ sudo apt install some-package
The following packages have unmet dependencies:
 some-package : Depends: libfoo (>= 2.0) but 1.8 is to be installed
E: Unable to correct problems, you have held broken packages.

(A) is apt deliberately declining an upgrade; the system is healthy. (B) is a version mismatch in a required library, and left alone it will block other installs too. Telling which symptom you have is the first step.

Assumptions (target environment)

  • OS: Ubuntu / Debian-based distributions (anything using apt / dpkg)
  • You can use sudo
  • (B) is most common right after adding a third-party PPA or a manual .deb

Why does a package get "kept back"?

Conclusion: apt upgrade is conservative - it refuses upgrades that would add new packages or remove existing ones. So kernels and metapackages, whose updates add dependencies, get "kept back". Ubuntu's phased updates also hold updates temporarily.

There are two main reasons "kept back" shows up with apt upgrade.

Reason Typical packages How to clear
Upgrade needs new dependencies Kernel (linux-generic etc.) apt full-upgrade
Upgrade needs removals Metapackages / transitional apt full-upgrade
Phased updates mid-rollout Anything (Ubuntu only) Wait / verify

The first is the most common. To stay safe, apt upgrade will update what you have but will not add new packages or remove obsolete ones. A kernel update brings a new ABI-versioned package, which trips this rule and gets kept back.

To allow additions and removals and upgrade everything together, use full-upgrade (dist-upgrade with apt-get).

$ sudo apt full-upgrade

Ubuntu phased updates roll out over several days instead of all at once. If your machine is not yet in the rollout percentage, that one update stays kept back. In that case it arrives on its own within a few days. To check now, inspect the candidate:

$ apt-cache policy <package-name>

How do I check and release explicitly held packages?

Conclusion: Someone (maybe you) may have run apt-mark hold to intentionally pin a package. List them with apt-mark showhold, and release with apt-mark unhold <pkg> if no longer needed. dpkg --get-selections shows them too.

If a package still won't update even after full-upgrade, it is likely held (pinned). A hold means "do not upgrade this", used to lock a known-good version (kernels, drivers, etc.).

First, list held packages.

$ apt-mark showhold
nvidia-driver-535
linux-image-generic

Those names are excluded from upgrades. dpkg shows the same thing.

$ dpkg --get-selections | grep hold
nvidia-driver-535				hold

When the pin is no longer needed, release the hold. After that the package returns to normal upgrade handling.

# Release the hold
$ sudo apt-mark unhold nvidia-driver-535

# To pin it instead
$ sudo apt-mark hold nvidia-driver-535

Carelessly un-holding an intentionally held package (e.g. a verified driver) can change behavior at the next upgrade. Do not release a hold until you know why it exists. If you are unsure, find out who set it and when (team policy, a provisioning script) first.

Why do unmet dependencies happen?

Conclusion: unmet dependencies means a required dependency version cannot be obtained or reconciled. The causes boil down to mixed repositories (PPAs, manual .deb), a stale apt update, an interrupted install, or pinning. The Depends: line in the error is your direct clue.

When you hit unmet dependencies, read the error body first. It states which dependency, under which version constraint, cannot be satisfied.

The following packages have unmet dependencies:
 packageA : Depends: libbar (>= 3.0) but it is not going to be installed
           Depends: libbaz (= 1.2) but 1.4 is to be installed

Depends: libbar (>= 3.0) but ... means "libbar 3.0 or newer is required, but it cannot be installed / a different version is about to be". The causes fall into four buckets.

Cause Typical situation Direction
Mixed repositories PPA / manual .deb / mixed Ubuntu releases Remove the PPA / --fix-broken
Stale apt update apt doesn't know the new dependency version apt update, then retry
Previous install interrupted Power loss / kill ended apt mid-operation dpkg --configure -a
apt pinning (priorities) A version pinned in /etc/apt/preferences Revisit the pin

The first dominates: an external PPA or stray .deb demands a dependency version that clashes with the official repository. apt-cache policy shows which repository a dependency comes from.

$ apt-cache policy libbar
libbar:
  Installed: 2.8-1
  Candidate: 2.8-1
  Version table:
     3.0-1 500 500 https://ppa.example/ubuntu jammy/main amd64 Packages
 *** 2.8-1 500 500 http://archive.ubuntu.com/ubuntu jammy/main amd64 Packages

Seeing which repository the candidate and the required version come from tells you whether mixing is the cause.

How do I repair broken dependencies?

Conclusion: The go-to is sudo apt --fix-broken install (formerly apt-get -f install), which tries to resolve half-finished dependencies. If an interruption is the cause, run dpkg --configure -a first. If the repo data is just stale, apt update often fixes it.

Repair in order of least impact. Don't force-remove packages up front - let apt resolve it.

First refresh the lists, then attempt the automatic repair.

$ sudo apt update
$ sudo apt --fix-broken install

--fix-broken (-f) detects packages with broken dependencies and proposes/applies the missing additions or unnecessary removals. If a previous apt stopped mid-operation, configure the "unpacked but not configured" packages first.

$ sudo dpkg --configure -a
$ sudo apt --fix-broken install

When apt proposes to remove a package, always read what will be removed. If the proposal involves removing important packages you did not expect, stop before answering yes.

The widely shared sudo dpkg -i --force-depends *.deb and --force-all bypass dependency checks and install anyway - it may pass now but breaks worse later. The --force-* options are a last resort; fix the root cause (mixed repos, pinning) first.

The standard recovery sequence, in order:

sudo apt update
sudo dpkg --configure -a
sudo apt --fix-broken install
sudo apt full-upgrade

How do I get resolution options from aptitude?

Conclusion: For complex conflicts that apt --fix-broken install cannot resolve, aptitude proposes multiple solutions interactively. You can reject options you dislike, so it finds a middle ground more flexibly than apt.

Even when apt gives up on a conflict, aptitude walks through staged solutions (what to hold, what to downgrade, and so on). It usually isn't installed by default, so add it.

$ sudo apt install aptitude
$ sudo aptitude install <package-name>

When a dependency can't be satisfied, aptitude offers solutions like Accept this solution? [Y/n/q/?]. Press n for the next option, y to accept - so you pick a solution you are comfortable with. The finer control over apt's "all or nothing" is the advantage.

aptitude proposals can also include "remove a pile of packages" solutions. Always review the removals and downgrades of a proposed solution before accepting. Blindly taking the first option is no better than forcing it with apt.

Checklist when it still won't fix

Conclusion: Tell held from broken, and for broken apply "update -> configure -> fix-broken" in order. If you suspect mixed repositories, removing that PPA and re-evaluating is the shortest path.

  • [ ] Determined whether the symptom is "kept back" (held) or "unmet dependencies" (broken)?
  • [ ] If kept back, tried apt full-upgrade (and waited if it's phased updates)?
  • [ ] Checked apt-mark showhold for an intentional hold?
  • [ ] Read the Depends: line in the unmet dependencies error?
  • [ ] Tried sudo apt update -> dpkg --configure -a -> apt --fix-broken install in order?
  • [ ] Used apt-cache policy <dep> to spot mixed repos (PPA / manual .deb)?
  • [ ] Fixed the root cause (pinning / mixing) before forcing with --force-*?
  • [ ] Reviewed aptitude solutions for complex conflicts?

Next Reading