Package operations are serialised by a lock. A second apt or dpkg waits or fails. This is protecting you: two processes writing the package database concurrently corrupts it.
There are several locks and the message tells you which:
| Lock | Guards |
|---|---|
/var/lib/dpkg/lock-frontend | The high-level frontend, one apt or dpkg at a time |
/var/lib/dpkg/lock | The dpkg database itself |
/var/lib/apt/lists/lock | The package index, held during apt update |
/var/cache/apt/archives/lock | The download cache |
Who has it?
The error usually says:
E: Could not get lock /var/lib/dpkg/lock-frontend.
It is held by process 2841 (unattended-upgr)
Otherwise:
sudo lsof /var/lib/dpkg/lock-frontend
sudo fuser -v /var/lib/dpkg/lock-frontend
ps -o pid,etime,cmd -p 2841
etime matters. A process running for 30 seconds is working; one running for three hours is stuck.
It is usually unattended-upgrades
Debian and Ubuntu install security updates automatically, typically shortly after boot. A fresh cloud instance running your provisioning script hits this reliably, because cloud-init and unattended-upgrades start at roughly the same moment.
Wait for it. It finishes in a few minutes:
while sudo fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do
echo "waiting for dpkg lock"
sleep 5
done
That loop belongs in any provisioning script that installs packages on a fresh machine.
You can also ask apt to wait, which is cleaner:
sudo apt-get -o DPkg::Lock::Timeout=300 install -y curl
Available since apt 2.0, on Ubuntu 20.04 and later. It waits up to five minutes for the lock rather than failing immediately, and it is the right answer for automation.
Do not delete the lock file
The common advice is sudo rm /var/lib/dpkg/lock*. It works when nothing holds the lock and it is dangerous when something does, because you then have two processes writing the package database. That produces a half-configured system that is genuinely tedious to repair.
If a process is truly stuck, stop it properly:
sudo systemctl stop unattended-upgrades
sudo kill 2841 # SIGTERM, lets dpkg finish the current step
Only escalate to kill -9 if SIGTERM is ignored for several minutes, and expect to run the repair below afterwards.
Repairing after an interruption
sudo dpkg --configure -a
sudo apt-get install -f
dpkg --configure -a completes any package left half-configured. apt-get install -f fixes broken dependencies. Run both after any killed package operation, and before trying the install again.
If the database itself is inconsistent:
sudo rm -f /var/lib/dpkg/updates/*
sudo dpkg --configure -a
Those are transaction journal fragments from an interrupted run.
Disabling automatic updates
On a machine where you control patching, or on a build image:
sudo systemctl disable --now unattended-upgrades apt-daily.timer apt-daily-upgrade.timer
Both timers matter: apt-daily refreshes the index and apt-daily-upgrade installs. Disabling only one leaves the other still taking the lock.
For cloud instances, do it in user data before anything else runs.
Be deliberate about this. Turning off automatic security updates means you own patching, and on an internet-facing machine that is a real commitment.
In Docker builds
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
A build container has no unattended-upgrades, so this error in a Dockerfile almost always means two RUN steps racing, which cannot happen, or a stale lock baked into a base image. The latter comes from an image built by copying a filesystem from a running machine.
RUN rm -f /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock && dpkg --configure -a
Here deleting is safe, because a build layer has exactly one process.
Ansible and configuration management
- name: Install packages
apt:
name: curl
state: present
lock_timeout: 300
become: true
lock_timeout uses the same apt mechanism. Without it, the first playbook run against a fresh instance fails roughly as often as it succeeds.
A checklist
- Read the process name in the error, or use
lsofon the lock file. ps -o pid,etime,cmd -p <pid>. Check how long it has been running.unattended-upgr→ wait. It finishes in minutes.- In scripts, use
-o DPkg::Lock::Timeout=300rather than a retry loop. - Never delete the lock file while a process holds it.
- Genuinely stuck →
systemctl stop, thenSIGTERM, before anything harsher. - After any interruption →
dpkg --configure -aandapt-get install -f. - Build images → disable
apt-daily.timerandapt-daily-upgrade.timer, both.
Frequently Asked Questions
Why does this happen on a brand new cloud instance?
Because unattended-upgrades starts automatically shortly after boot to install security patches, and your provisioning script starts at roughly the same moment. The two race for the dpkg lock and yours usually loses. It is not a misconfiguration, it is two legitimate things wanting the same resource. Add -o DPkg::Lock::Timeout=300 to your apt commands, or a wait loop at the top of the script, and the race resolves itself.
Is it safe to delete the lock file?
Only when nothing holds it, which is exactly when you do not need to. If a process is genuinely mid-transaction, removing the lock lets a second process write the package database concurrently, and the result is a half-configured system that takes real effort to repair. Check with lsof first. If something is stuck, stop it properly with systemctl stop or SIGTERM, and run dpkg --configure -a afterwards.
What is the difference between lock-frontend and the other locks?
lock-frontend serialises the high-level tools so only one apt or dpkg frontend runs at a time. /var/lib/dpkg/lock guards the package database itself during a transaction. /var/lib/apt/lists/lock is held while apt update rewrites the package index, and /var/cache/apt/archives/lock during downloads. Which one the error names tells you roughly what stage the other process is at, though the fix is the same: find it and wait.
How do I make apt wait instead of failing?
Pass -o DPkg::Lock::Timeout=300, available since apt 2.0 and therefore on Ubuntu 20.04 and later. It waits up to the given number of seconds for the lock rather than exiting immediately, which is much cleaner than a shell retry loop and behaves properly if the lock is released partway through. Ansible's apt module exposes the same thing as lock_timeout, and setting it removes most first-run failures against fresh instances.
Should I disable unattended-upgrades?
On a build image or a machine where you manage patching through another mechanism, yes, and disable both apt-daily.timer and apt-daily-upgrade.timer since they do different jobs. On an ordinary internet-facing server, think carefully: automatic security updates are doing real work, and turning them off means you now own the responsibility for applying patches promptly. Waiting for the lock is usually the better trade.