Resolver o erro do apt "Could not get lock"

Publicado a 15 min de leitura

Porque é que o apt fica de repente bloqueado, que processo está por trás disso, como o encontrar com lsof e fuser e como remover o ficheiro de bloqueio sem danificar a base de dados de pacotes.

Quer instalar rapidamente mais um pacote e o apt aborta ao fim de um segundo. Em vez da lista de pacotes aparece ali uma linha que é pesquisada milhões de vezes por todo o mundo: Could not get lock. O reflexo de muitos guias é apagar de imediato o ficheiro de bloqueio. É precisamente esse reflexo que transforma, com regularidade, um banal caso de espera numa base de dados de pacotes danificada. Este artigo percorre a ordem que funciona num sistema em produção: primeiro apurar quem está a bloquear, depois esperar e só no fim intervir.

Todos os comandos correm como root. Se trabalha como utilizador normal, anteponha sudo. E, desde já, para enquadrar o tema: isto diz respeito exclusivamente ao Debian e ao Ubuntu. No AlmaLinux, Rocky Linux, RHEL e Oracle Linux não existe apt-get nem /var/lib/dpkg, o dnf resolve a questão de forma completamente diferente, veja a secção sobre as diferenças entre sistemas mais abaixo.

A mensagem de erro na íntegra

Consoante a versão e consoante aquilo que o apt estava a tentar fazer, a saída tem um aspeto diferente. Estas são as variantes com que se vai deparar:

E: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 1234 (unattended-upgr)
N: Be aware that removing the lock file is not a solution and may break your system.
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?
E: Could not get lock /var/lib/dpkg/lock - open (11: Resource temporarily unavailable)
E: Unable to lock the administration directory (/var/lib/dpkg/), is another process using it?
E: Could not get lock /var/lib/apt/lists/lock. It is held by process 987 (apt-get)
E: Unable to lock directory /var/lib/apt/lists/
dpkg: error: dpkg frontend lock is locked by another process
dpkg: error: dpkg status database is locked by another process

A localização portuguesa comunica o mesmo com "Não foi possível obter acesso exclusivo" ou "Não foi possível criar acesso exclusivo ao directório de administração". O importante é a indicação entre parênteses: o nome do processo. unattended-upgr, apt-get, aptitude, packagekitd ou dpkg já lhe dizem onde tem de procurar.

Quatro ficheiros de bloqueio, quatro mensagens diferentes

O apt e o dpkg não bloqueiam num único ponto, mas em quatro. O ficheiro indicado na mensagem revela em que fase surgiu o conflito:

  • /var/lib/apt/lists/lock protege as listas de pacotes descarregadas. Esta mensagem surge com apt update.
  • /var/cache/apt/archives/lock protege o diretório de transferência dos ficheiros .deb. Esta mensagem surge enquanto o apt vai buscar pacotes.
  • /var/lib/dpkg/lock-frontend é o bloqueio de nível mais alto. Garante que apenas um frontend (apt, apt-get, aptitude, Ansible, um script de instalação) fala com o dpkg de cada vez. É esta a mensagem que verá com mais frequência.
  • /var/lib/dpkg/lock protege a própria base de dados de estado. Quem detém este bloqueio está mesmo a escrever neste momento em /var/lib/dpkg/status.

Os quatro ficheiros estão vazios. Não contêm dados, não contêm PID, não contêm nada. O bloqueio não está no conteúdo, mas num flock sobre o descritor de ficheiro aberto. É este o ponto decisivo que a maioria dos guias omite.

Porque é que apagar às cegas pode danificar a base de dados de pacotes

Como o bloqueio está preso ao descritor de ficheiro e não ao nome do ficheiro, ao apagar acontece o seguinte: o processo em execução mantém o seu descritor e continua a trabalhar imperturbável. O ficheiro desapareceu do diretório, mas para ele continua a existir. A sua segunda invocação do apt cria um ficheiro novo com o mesmo nome, bloqueia-o com sucesso e julga ter o caminho livre.

A partir desse momento, dois processos escrevem em simultâneo em /var/lib/dpkg/status, descompactam ficheiros em paralelo para o mesmo diretório de destino e disparam os triggers um do outro. O resultado vai desde pacotes meio configurados até uma base de dados de estado que o dpkg já não consegue ler. É exatamente disso que o próprio apt avisa com a linha N: Be aware that removing the lock file is not a solution and may break your system.

Remover o ficheiro de bloqueio só é admissível quando estiver comprovado que já não corre nenhum processo que o detenha. A prova é o cerne deste guia, não o rm.

O caso mais frequente: a atualização automática está a decorrer

Em cerca de nove de cada dez casos num servidor acabado de instalar, o culpado é inofensivo e legítimo: unattended-upgrades. O Ubuntu ativa por predefinição as atualizações de segurança não assistidas nas imagens de servidor e de cloud, e dois timers do systemd desencadeiam o processo:

  • apt-daily.timer corre às 06:00 e às 18:00 com um atraso aleatório até doze horas e atualiza as listas de pacotes.
  • apt-daily-upgrade.timer corre às 06:00 com um atraso aleatório até 60 minutos e instala as atualizações de segurança.

O atraso aleatório é a razão pela qual o erro parece surgir a horas completamente arbitrárias. Nas imagens de cloud junta-se ainda o primeiro arranque: o cloud-init executa ele próprio um apt update no primeiro boot. Quem inicia sessão dois minutos depois do aprovisionamento e quer instalar algo de imediato esbarra quase inevitavelmente no bloqueio. Por isso, ao preparar um servidor novo, compensa seguir a ordem da nossa checklist para novos servidores root: primeiro respirar fundo, depois instalar.

O estado da atualização automática consulta-se assim:

systemctl list-timers 'apt-daily*'
systemctl status unattended-upgrades.service
journalctl -u apt-daily-upgrade.service --since "-2h" --no-pager
tail -n 30 /var/log/unattended-upgrades/unattended-upgrades.log

Quem detém o bloqueio? Diagnóstico com lsof e fuser

Antes de qualquer intervenção coloca-se a questão de saber se ainda há alguém a trabalhar. Duas ferramentas respondem a isso de forma fiável. Se faltarem, vêm dos pacotes lsof e psmisc, que, como é evidente, só consegue instalar depois de o bloqueio desaparecer. Por isso, em sistemas de produção, ambas pertencem ao equipamento de base.

lsof /var/lib/dpkg/lock-frontend
lsof /var/lib/dpkg/lock
lsof /var/cache/apt/archives/lock
lsof /var/lib/apt/lists/lock

Uma saída típica tem este aspeto:

COMMAND     PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
unattended 1234 root    5uW  REG  254,1        0 1049 /var/lib/dpkg/lock-frontend

O W a seguir ao número do descritor de ficheiro significa: bloqueio de escrita colocado. Só esta entrada bloqueia realmente o apt, um simples handle aberto sem W não o faz. Aqui está portanto tudo em ordem, o processo está a trabalhar.

Se, pelo contrário, não vier saída nenhuma, já ninguém detém o bloqueio. Conte com o facto de o lsof devolver, neste caso normal, o valor de retorno 1, sem qualquer texto de erro. O mesmo vale para o fuser. Num script com set -e ou numa cadeia ligada por &&, o diagnóstico aborta precisamente quando o resultado é bom. Escreva aí lsof /var/lib/dpkg/lock-frontend || true.

Uma ressalva importante quanto ao valor probatório: uma saída vazia só significa mesmo "ninguém está a bloquear" se o ficheiro de bloqueio não tiver sido apagado antes. Se tiver sido removido enquanto um processo ainda o detinha, esse processo continua a segurar o inode órfão, mas sob o nome do ficheiro o lsof já não vê nada. Por isso, verifique sempre também a lista de processos.

Sem o lsof, o fuser faz o mesmo:

fuser -v /var/lib/dpkg/lock-frontend

E um olhar sobre a lista de processos mostra ainda há quanto tempo a operação decorre. A coluna etimes indica o tempo de execução em segundos, o que ajuda a avaliar a situação:

ps -eo pid,ppid,etimes,stat,cmd | grep -E 'apt|dpkg|unattended' | grep -v grep

Interprete o resultado assim:

  • Tempo de execução abaixo de dez minutos, estado S ou R: funcionamento normal. Esperar.
  • Tempo de execução acima de uma hora, acesso à rede, servidores espelho lentos: continua a ser plausível. Verifique com tail -f /var/log/apt/term.log se alguma coisa se mexe.
  • Estado D (uninterruptible sleep) durante muito tempo: o processo está preso no caminho de entrada e saída. A causa costuma ser um disco cheio ou defeituoso, não o apt em si.
  • Estado T (parado): alguém suspendeu a operação com Ctrl+Z. Retome-a com kill -CONT PID.
  • O processo já não existe e o bloqueio permanece: agora, e só agora, remover o ficheiro de bloqueio é legítimo.

Uma causa frequente e subestimada é uma partição cheia: o dpkg aborta a meio da descompactação e deixa exatamente este estado. Se df -h /var mostrar valores próximos dos 100%, leia primeiro como libertar espaço num disco cheio em Linux e só depois repare a gestão de pacotes.

Esperar corretamente em vez de abortar: DPkg::Lock::Timeout

Desde o apt 2.x existe uma opção que torna dispensável boa parte dos aborrecimentos em scripts. Em vez de abortar de imediato, o apt espera um número definido de segundos pela libertação:

apt-get -o DPkg::Lock::Timeout=60 install -y htop

O valor -1 significa espera ilimitada. De forma permanente, defina isto num ficheiro de configuração próprio. A extensão em falta não é um lapso, o apt lê o ficheiro mesmo sem .conf:

echo 'DPkg::Lock::Timeout "300";' > /etc/apt/apt.conf.d/99lock-timeout
apt-config dump DPkg::Lock::Timeout

A segunda linha é a contraprova. Tem de devolver DPkg::Lock::Timeout "300";, e só então o ficheiro está mesmo em vigor.

E agora a limitação que quase nenhum guia refere e que faz a diferença quando a coisa aperta: a opção não cobre os quatro bloqueios. Medido em Debian 11, 12 e 13, bem como em Ubuntu 22.04 e 24.04, sempre com um processo externo a deter o bloqueio através de fcntl:

BloqueioO apt espera com DPkg::Lock::Timeout?
/var/lib/dpkg/lock-frontendsim, exatamente o tempo definido
/var/lib/dpkg/locksim
/var/cache/apt/archives/locknão, aborta em menos de um segundo
/var/lib/apt/lists/locknão, aborta em menos de um segundo

Na prática, isto quer dizer duas coisas. Primeiro: em apt-get update a opção não serve de nada, porque ali está em causa o bloqueio das listas. Mesmo com DPkg::Lock::Timeout=-1 a invocação aborta de imediato com E: Could not get lock /var/lib/apt/lists/lock e valor de retorno 100, em vez de esperar. Segundo: mesmo em install, o timeout só ajuda enquanto o bloqueador detiver o bloqueio do frontend. Se um processo paralelo estiver preso numa transferência e detiver assim o bloqueio do arquivo, o apt também não espera um único segundo.

Por isso, em roles de Ansible, scripts de cloud-init e pipelines de deploy, junta-se ainda um ciclo de repetição exterior, ou então toda a ação é serializada através de flock:

for i in $(seq 30); do apt-get update && break; sleep 10; done
flock /var/lib/apt/lists/lock apt-get update

Em Debian 12, Debian 13, Ubuntu 22.04 e Ubuntu 24.04 a opção existe. Em sistemas muito antigos (Debian 9, Ubuntu 16.04) o apt não a conhece e ignora-a em silêncio, sem lançar qualquer erro.

Quando já não corre mesmo nenhum processo: remover o ficheiro de bloqueio

Comprovou com lsof e ps que já ninguém trabalha sobre a gestão de pacotes. Só agora se segue a intervenção. Se ainda houver um processo que tenha mesmo de terminar, use primeiro o sinal amigável e nunca logo kill -9:

kill -TERM 1234

Um SIGTERM dá ao unattended-upgrades a hipótese de concluir de forma limpa a invocação do dpkg em curso. Já um SIGKILL a meio da descompactação deixa exatamente os pacotes meio instalados que depois terá de limpar com esforço. Depois do SIGTERM, espere pelo menos 30 segundos e verifique de novo.

Se a lista de processos estiver limpa, remova os ficheiros de bloqueio:

rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock /var/cache/apt/archives/lock /var/lib/apt/lists/lock

Os ficheiros voltam a ser criados automaticamente na invocação seguinte do apt. Não precisa de os criar à mão nem de lhes atribuir permissões específicas. Em contrapartida, isso também significa que apagar não repara permissões erradas nem um proprietário errado, apenas elimina o nome. Quem esperar daí uma reparação está a procurar no sítio errado. E ainda mais cuidadoso do que o rm é limitar-se a esvaziar os ficheiros, por exemplo com : > /var/lib/dpkg/lock-frontend: assim o inode mantém-se e um processo antigo ainda em execução continua visível no lsof.

Depois da intervenção: dpkg --configure -a

Este passo não é opcional. Uma operação interrompida deixa pacotes no estado "descompactado, mas não configurado". O apt recusa-se então com:

E: dpkg was interrupted, you must manually run 'dpkg --configure -a' to correct the problem.

O comando executa todos os passos de configuração pendentes:

dpkg --configure -a

Segue-se depois a verificação de dependências quebradas:

apt-get --fix-broken install -y
apt-get check

Um detalhe interessante para a verificação posterior: em /var/lib/dpkg/updates/ encontra-se o journal do dpkg. Se o diretório estiver vazio depois de dpkg --configure -a, ficou tudo tratado. Se lá continuarem ficheiros numerados, a operação não chegou ao fim.

Se ainda assim correu mal: erros subsequentes e caminho de volta

É aqui que os outros guias acabam. Estas mensagens aparecem quando se apagou cedo demais ou se matou o processo com demasiada dureza:

dpkg: error processing package nginx (--configure):
 package is in a very bad inconsistent state; you should
 reinstall it before attempting configuration
Errors were encountered while processing:
 nginx
E: Sub-process /usr/bin/dpkg returned an error code (1)

A saída passa por uma remoção forçada do pacote danificado e por uma reinstalação. Use --force-remove-reinstreq exclusivamente para o pacote afetado, nunca de forma generalizada:

dpkg --remove --force-remove-reinstreq nginx
apt-get install -y nginx

Uma segunda variante diz respeito às listas de ficheiros:

dpkg: warning: files list file for package 'libssl3' missing; assuming package has no files currently installed

Isso resolve-se com uma reinstalação do mesmo pacote através de apt-get install --reinstall. Que pacotes se encontram afinal num estado inconsistente, mostra-o:

dpkg --audit

No pior dos casos, o próprio /var/lib/dpkg/status está danificado, o que se reconhece por mensagens como dpkg: unrecoverable fatal error, aborting: parsing file '/var/lib/dpkg/status'. Nesse caso ajudam duas cópias de segurança que o sistema cria automaticamente: /var/lib/dpkg/status-old e as cópias rodadas diariamente em /var/backups/dpkg.status.0 até dpkg.status.6.gz. Reponha a mais recente das duas antes de pensar sequer em reinstalar o sistema. Antes disso, faça obrigatoriamente uma cópia de segurança do ficheiro danificado.

Diferenças entre os sistemas

"Uma solução para todos" não existe aqui, o ponto de partida é claramente diferente:

  • Ubuntu 22.04 e 24.04: o unattended-upgrades está ativo nas imagens de servidor, o erro faz parte do quotidiano. A isso junta-se o needrestart, que abre uma caixa de diálogo interativa depois de cada instalação e mantém a operação em aberto, com bloqueio incluído, até alguém confirmar. Em scripts, defina por isso DEBIAN_FRONTEND=noninteractive.
  • Debian 12 e Debian 13: os timers apt-daily.timer e apt-daily-upgrade.timer também existem, mas se a atualização automática acontece de facto depende da imagem e de /etc/apt/apt.conf.d/20auto-upgrades. Verificar em vez de presumir.
  • Containers: numa imagem Docker não corre systemd nem unattended-upgrades. Um bloqueio ali significa quase sempre passos paralelos no build ou uma camada em cache com um ficheiro de bloqueio esquecido. Quem constrói imagens com regularidade encontra o ponto de partida no nosso artigo sobre Docker em Debian e Ubuntu.
  • Sistemas de desktop: ali é muitas vezes o packagekitd ou o gestor gráfico de atualizações que detém o bloqueio, não o apt.
  • AlmaLinux, Rocky Linux e RHEL: ali o problema não existe nesta forma, o dnf usa /var/run/dnf.pid e espera por predefinição, em vez de abortar. A mensagem é então Waiting for process with pid ... to finish. Em que mais esta família se distingue, mostra-o o artigo sobre htop em AlmaLinux, Rocky e RHEL.

Como reconhecer que está tudo novamente limpo

Quatro verificações que, em conjunto, são conclusivas:

dpkg --audit
apt-get check
apt-get --fix-broken install -y
apt-get update

No caso ideal, o dpkg --audit não devolve absolutamente nada. O apt-get check termina com as linhas da leitura das listas de pacotes e sem erros. O apt-get --fix-broken install comunica 0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded. E o apt-get update corre até ao fim sem mensagem de bloqueio. Além disso, ls /var/lib/dpkg/updates/ deve mostrar um diretório vazio, e um olhar sobre /var/log/dpkg.log deve terminar as últimas ações com o estado status installed em vez de half-configured:

tail -n 20 /var/log/dpkg.log

Prevenir em vez de reparar

Para que o erro nem chegue a tornar-se um sorvedouro de tempo, ajudam quatro hábitos:

  1. Definir o timeout e mesmo assim repetir. DPkg::Lock::Timeout em /etc/apt/apt.conf.d/99lock-timeout faz o apt esperar no bloqueio do frontend e no do dpkg, em vez de abortar. Como o bloqueio do arquivo e o das listas não entram nessa conta, acrescenta-se em scripts um ciclo de repetição exterior. Os dois em conjunto cobrem praticamente todos os incidentes.
  2. Nunca atualizar numa sessão SSH simples. Se a ligação cair durante apt upgrade, o dpkg aborta a meio da operação. Inicie as atualizações mais longas dentro de tmux ou screen. As bases estão no artigo sobre ligar-se ao servidor por SSH.
  3. Evitar o Ctrl+C durante o processo. Durante a transferência, uma interrupção é inofensiva; durante a descompactação e a configuração, produz exatamente os pacotes meio instalados da secção acima.
  4. Não deixar as suas próprias rotinas de manutenção colidirem com os timers do sistema. Quem faz correr uma atualização própria por agendamento, coloca-a desfasada no tempo e com timeout. Como configurar isso de forma limpa está nos artigos sobre cronjobs em Linux e sobre serviços systemd próprios.

E ainda uma nota sobre a saída aparentemente mais fácil: apt remove unattended-upgrades elimina de facto os conflitos de bloqueio, mas retira-lhe também as atualizações de segurança automáticas. Num servidor acessível a partir da internet, é um mau negócio. Bem mais sensato é manter a atualização automática e tornar pacientes os seus próprios processos.


Em resumo: lsof sobre o ficheiro de bloqueio indicado, verificar a lista de processos, esperar. Só quando estiver comprovado que já nada corre é que se removem os ficheiros de bloqueio, e a seguir sempre dpkg --configure -a e apt-get check. Com DPkg::Lock::Timeout na configuração do apt e um ciclo de repetição em torno de apt-get update, o resto resolve-se sozinho.

Perguntas frequentes

Posso simplesmente apagar o ficheiro de bloqueio?
Só se tiver comprovado antes, com lsof ou fuser, que já nenhum processo o detém. O bloqueio está preso ao descritor de ficheiro aberto, não ao nome do ficheiro. Se apagar enquanto um processo trabalha, ficam a seguir dois processos em simultâneo sobre a mesma base de dados de pacotes, e isso danifica-a.
Quanto tempo devo esperar antes de intervir?
Com o unattended-upgrades, dez a trinta minutos são normais; em atualizações grandes através de servidores espelho lentos, também pode demorar mais. Verifique com tail -f /var/log/apt/term.log se ainda há movimento. Enquanto ali forem aparecendo linhas, a operação está a decorrer e não deve intervir.
O que significa o nome de processo unattended-upgr na mensagem de erro?
É a atualização de segurança automática, iniciada pelos timers do systemd apt-daily.timer e apt-daily-upgrade.timer. O nome está truncado a 15 caracteres. Deve deixar esta operação chegar ao fim, em vez de a interromper.
Porque é que preciso do dpkg --configure -a depois de remover o ficheiro de bloqueio?
Uma operação interrompida deixa pacotes no estado descompactado, mas não configurado. O dpkg --configure -a trata desses passos pendentes. Sem este comando, o apt recusa qualquer nova instalação com a mensagem dpkg was interrupted.
Como evito o erro em scripts e em roles de Ansible?
Com apt-get -o DPkg::Lock::Timeout=300 em vez de um ciclo de espera sobre nomes de processos. De forma permanente, escreva DPkg::Lock::Timeout "300"; em /etc/apt/apt.conf.d/99lock-timeout; o valor -1 significa espera ilimitada. Importante: a opção só atua no bloqueio do frontend do dpkg e no bloqueio do dpkg. No bloqueio do arquivo e no das listas o apt continua a não esperar, e por isso, em apt-get update, está comprovado que não serve de nada. Aí precisa de um ciclo de repetição próprio, por exemplo: for i in $(seq 30); do apt-get update && break; sleep 10; done
Este erro também existe em AlmaLinux ou Rocky Linux?
Nesta forma, não. O dnf bloqueia através de /var/run/dnf.pid e espera por predefinição que a outra operação termine, em vez de abortar. A mensagem ali é Waiting for process with pid ... to finish.
O apt continua a indicar erros num pacote isolado depois da reparação, e agora?
Verifique com dpkg --audit qual é o pacote afetado, remova exatamente esse com dpkg --remove --force-remove-reinstreq PACOTE e instale-o a seguir de novo. Nunca aplique a opção de forma generalizada a todos os pacotes.

apt dpkg Debian Ubuntu Gestão de pacotes Resolução de problemas unattended-upgrades Linux