Corrigindo dependências quebradas e pacotes retidos no apt

Corrigindo dependências quebradas e pacotes retidos no apt

Qual a diferença entre pacotes retidos e dependências quebradas?

Conclusão: São problemas diferentes. Retido (held) significa que um pacote foi intencionalmente excluído de atualizações - não é um erro. Dependências quebradas significa que uma dependência necessária não pode ser satisfeita, então instalações ou atualizações não podem ser concluídas. O primeiro é tratado com apt-mark, o segundo com apt --fix-broken install.

As pessoas tendem a agrupar esses dois sintomas como "um problema de dependência", mas as causas e correções diferem.

# (A) retido: uma atualizacao foi simplesmente mantida de lado. Nao e um erro.
$ sudo apt upgrade
The following packages have been kept back:
  linux-generic nvidia-driver-535
# (B) quebrado: uma dependencia nao pode ser satisfeita e a operacao para. Isso e anormal.
$ 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) é o apt deliberadamente recusando uma atualização; o sistema está saudável. (B) é uma incompatibilidade de versão em uma biblioteca necessária, e se deixado assim vai bloquear outras instalações também. Identificar qual sintoma você tem é o primeiro passo.

Premissas (ambiente alvo)

  • SO: Ubuntu / distribuições baseadas em Debian (qualquer uma usando apt / dpkg)
  • Você pode usar sudo
  • (B) é mais comum logo após adicionar um PPA de terceiros ou um .deb manual

Por que um pacote fica "kept back"?

Conclusão: apt upgrade é conservador - ele não realiza uma atualização que requer remover um pacote existente (ele vai instalar novos pacotes quando necessário para satisfazer dependências). Então metapacotes e kernels cuja atualização precisa de uma remoção ficam "kept back". As phased updates do Ubuntu também retém atualizações temporariamente.

Há duas razões principais para "kept back" aparecer com apt upgrade.

Razão Pacotes típicos Como resolver
Atualização requer uma remoção Metapacotes / transicionais / kernel apt full-upgrade
Phased updates em andamento Qualquer um (apenas Ubuntu) Aguardar / verificar

Para se manter seguro, apt upgrade vai adicionar novos pacotes quando necessário para satisfazer dependências, mas nunca remove um pacote que você já tem. Se uma atualização requer remover um pacote instalado, essa atualização é pulada e mantida de lado (kept back). Atualizações de metapacotes de kernel podem cair nessa regra.

Para permitir remoções e atualizar todo o sistema junto, use full-upgrade (dist-upgrade com apt-get).

$ sudo apt full-upgrade

As phased updates do Ubuntu são distribuídas ao longo de vários dias em vez de todas de uma vez. Se sua máquina ainda não está na porcentagem de distribuição, aquela atualização fica mantida de lado. Nesse caso, ela chega por conta própria em alguns dias. Para verificar agora, inspecione o candidato:

$ apt-cache policy <package-name>

Como verificar e liberar pacotes explicitamente retidos?

Conclusão: Alguém (talvez você) pode ter executado apt-mark hold para fixar intencionalmente um pacote. Liste-os com apt-mark showhold, e libere com apt-mark unhold <pkg> se não for mais necessário. dpkg --get-selections também mostra.

Se um pacote ainda não atualiza mesmo após full-upgrade, provavelmente está retido (pinned). Um hold significa "não atualize isso", usado para travar uma versão conhecida como boa (kernels, drivers, etc.).

Primeiro, liste os pacotes retidos.

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

Esses nomes estão excluídos de atualizações. dpkg mostra a mesma coisa.

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

Quando o pin não é mais necessário, libere o hold. Depois disso o pacote volta ao tratamento normal de atualizações.

# Liberar o hold
$ sudo apt-mark unhold nvidia-driver-535

# Para fixar em vez disso
$ sudo apt-mark hold nvidia-driver-535

Liberar descuidadamente um hold de um pacote intencionalmente retido (ex.: um driver verificado) pode alterar o comportamento na próxima atualização. Não libere um hold até saber por que ele existe. Se não tiver certeza, descubra quem definiu e quando (política da equipe, um script de provisionamento) primeiro.

Por que dependências não satisfeitas acontecem?

Conclusão: unmet dependencies significa que uma versão de dependência necessária não pode ser obtida ou reconciliada. As causas se resumem a repositórios misturados (PPAs, .deb manual), um apt update desatualizado, uma instalação interrompida ou pinning. A linha Depends: no erro é sua pista direta.

Quando você encontra unmet dependencies, leia o corpo do erro primeiro. Ele indica qual dependência, sob qual restrição de versão, não pode ser satisfeita.

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 ... significa "libbar 3.0 ou mais novo é necessário, mas não pode ser instalado / uma versão diferente está prestes a ser instalada". As causas se dividem em quatro categorias.

Causa Situação típica Direção
Repositórios misturados PPA / .deb manual / releases Ubuntu mistos Remover o PPA / --fix-broken
apt update desatualizado apt não conhece a nova versão da dependência apt update, depois tente novamente
Instalação anterior interrompida Queda de energia / kill encerrou apt no meio dpkg --configure -a
Pinning do apt (prioridades) Uma versão fixada em /etc/apt/preferences Revisar o pin

A primeira domina: um PPA externo ou .deb avulso demanda uma versão de dependência que conflita com o repositório oficial. apt-cache policy mostra de qual repositório uma dependência vem.

$ 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

Ver de qual repositório o candidato e a versão necessária vêm indica se a mistura é a causa.

Como reparar dependências quebradas?

Conclusão: O padrão é sudo apt --fix-broken install (anteriormente apt-get -f install), que tenta resolver dependências incompletas. Se uma interrupção é a causa, execute dpkg --configure -a primeiro. Se os dados do repositório estão apenas desatualizados, apt update frequentemente resolve.

Repare na ordem de menor impacto. Não force-remova pacotes de início - deixe o apt resolver.

Primeiro atualize as listas, depois tente o reparo automático.

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

--fix-broken (-f) detecta pacotes com dependências quebradas e propõe/aplica as adições faltantes ou remoções desnecessárias. Se um apt anterior parou no meio da operação, configure os pacotes "descompactados mas não configurados" primeiro.

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

Quando o apt propõe remover um pacote, sempre leia o que será removido. Se a proposta envolve remover pacotes importantes que você não esperava, pare antes de responder yes.

O amplamente compartilhado sudo dpkg -i --force-depends *.deb e --force-all ignoram verificações de dependência e instalam mesmo assim - pode passar agora mas quebra pior depois. As opções --force-* são último recurso; corrija a causa raiz (repos misturados, pinning) primeiro.

A sequência padrão de recuperação, em ordem:

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

Como obter opções de resolução do aptitude?

Conclusão: Para conflitos complexos que apt --fix-broken install não consegue resolver, aptitude propõe múltiplas soluções interativamente. Você pode rejeitar opções que não gosta, então ele encontra um meio-termo de forma mais flexível que o apt.

Mesmo quando o apt desiste de um conflito, aptitude percorre soluções em etapas (o que manter, o que fazer downgrade, etc.). Normalmente não está instalado por padrão, então adicione-o.

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

Quando uma dependência não pode ser satisfeita, aptitude oferece soluções como Accept this solution? [Y/n/q/?]. Pressione n para a próxima opção, y para aceitar - assim você escolhe uma solução com a qual está confortável. O controle mais fino sobre o "tudo ou nada" do apt é a vantagem.

Propostas do aptitude também podem incluir soluções "remover uma pilha de pacotes". Sempre revise as remoções e downgrades de uma solução proposta antes de aceitar. Aceitar cegamente a primeira opção não é melhor do que forçar com o apt.

Checklist quando ainda não resolve

Conclusão: Diferencie retido de quebrado, e para quebrado aplique "update -> configure -> fix-broken" em ordem. Se você suspeita de repositórios misturados, remover aquele PPA e reavaliar é o caminho mais curto.

  • [ ] Determinou se o sintoma é "kept back" (retido) ou "unmet dependencies" (quebrado)?
  • [ ] Se kept back, tentou apt full-upgrade (e aguardou se é phased updates)?
  • [ ] Verificou apt-mark showhold para um hold intencional?
  • [ ] Leu a linha Depends: no erro de unmet dependencies?
  • [ ] Tentou sudo apt update -> dpkg --configure -a -> apt --fix-broken install em ordem?
  • [ ] Usou apt-cache policy <dep> para identificar repos misturados (PPA / .deb manual)?
  • [ ] Corrigiu a causa raiz (pinning / mistura) antes de forçar com --force-*?
  • [ ] Revisou soluções do aptitude para conflitos complexos?

Próximas leituras