Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Ansible By James Joyner IV · · 9 min read

Ansible Error Guide: 'Could not get lock /var/lib/dpkg/lock' apt Module Failure

Fix Ansible's apt 'Failed to lock apt for exclusive operation / Could not get lock /var/lib/dpkg/lock-frontend' error: diagnose concurrent apt, unattended-upgrades, and stale locks.

  • #ansible
  • #troubleshooting
  • #errors
  • #apt

Exact Error Message

fatal: [web-01]: FAILED! => {
    "changed": false,
    "msg": "Failed to lock apt for exclusive operation: Could not get lock /var/lib/dpkg/lock-frontend.
It is held by process 1432 (unattended-upgr)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?"
}

You may also see Could not get lock /var/lib/apt/lists/lock or /var/lib/dpkg/lock, all variations of the same exclusive-lock problem from the apt module.

What the Error Means

Debian/Ubuntu’s package tooling (dpkg and apt) takes exclusive file locks so that only one package operation runs at a time. Ansible’s apt module wraps these tools, so when it tries to install or update packages while another process already holds the lock, it cannot proceed and fails immediately with Failed to lock apt for exclusive operation.

The error helpfully names the holding process when it can (here, unattended-upgr). This is a contention problem, not a broken package, and it is extremely common on freshly booted cloud instances where automatic updates run on startup.

Common Causes

  • unattended-upgrades is running automatic security updates in the background, especially in the first minutes after boot.
  • Another apt/dpkg process (a manual session, cloud-init, or a parallel Ansible run) holds the lock.
  • Two Ansible plays target the same host simultaneously (high forks plus per-host package tasks).
  • A previous apt/dpkg invocation crashed and left a stale lock file behind.
  • dpkg was interrupted mid-operation and the database needs dpkg --configure -a.

How to Reproduce the Error

Run an apt task on a host that is still applying boot-time updates:

- hosts: web
  become: true
  tasks:
    - name: Install nginx
      ansible.builtin.apt:
        name: nginx
        state: present
        update_cache: true
ansible-playbook web.yml -i inventory.ini --diff -vvv
fatal: [web-01]: FAILED! => {"changed": false, "msg": "Failed to lock apt for exclusive operation: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 1432 (unattended-upgr)"}

Diagnostic Commands

Confirm what holds the lock right now:

ansible web-01 -i inventory.ini -b -m command -a "lsof /var/lib/dpkg/lock-frontend"

Check whether unattended-upgrades or another apt process is active:

ansible web-01 -i inventory.ini -b -m command -a "ps aux | grep -E 'apt|dpkg|unattended'"

Inspect the dpkg state in case a previous run was interrupted:

ansible web-01 -i inventory.ini -b -m command -a "dpkg --audit"

Re-run the original play with verbosity to capture the exact lock path and holding PID:

ansible-playbook web.yml -i inventory.ini --diff -vvv

Step-by-Step Resolution

  1. Identify the holder. If it is unattended-upgr or cloud-init, the right fix is usually to wait, not to kill it mid-update.

  2. Make the apt task wait for the lock instead of failing. The cleanest approach is to retry until the lock clears:

- name: Install nginx (wait out boot-time updates)
  ansible.builtin.apt:
    name: nginx
    state: present
    update_cache: true
  register: apt_result
  until: apt_result is not failed
  retries: 30
  delay: 10
  1. Or wait for the lock file to be released before touching apt at all:
- name: Wait for apt lock to be released
  ansible.builtin.shell: "while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do sleep 5; done"
  changed_when: false
  1. If a previous run crashed and left things half-done, repair dpkg before continuing (verify the lock is genuinely stale first):
ansible web-01 -i inventory.ini -b -m command -a "dpkg --configure -a"
  1. Avoid concurrent apt operations. Do not run two plays against the same host at once, and serialize package tasks if your inventory fans out heavily.

  2. Re-run and confirm success:

ansible-playbook web.yml -i inventory.ini --diff
changed: [web-01]

Prevention and Best Practices

  • Build retry/until logic into every apt task so transient boot-time locks do not fail an otherwise healthy run.
  • On cloud images, either disable unattended-upgrades during provisioning or explicitly wait for cloud-init/apt to finish before running package tasks.
  • Never blindly delete lock files. Removing a lock that an active process holds can corrupt the dpkg database. Confirm the process is gone first.
  • Serialize package operations per host; do not launch overlapping plays that both run apt against the same machines.
  • Use dpkg --audit and dpkg --configure -a to recover cleanly from interrupted installs rather than forcing locks.
  • Keep update_cache deliberate; pair it with cache_valid_time to reduce how often you contend for the lists lock.
  • E: dpkg was interrupted, you must manually run 'dpkg --configure -a' — an interrupted install, often a precursor to lock contention.
  • Could not get lock /var/lib/apt/lists/lock — contention on the package-lists lock specifically.
  • MODULE FAILURE from the apt module — a different, lower-level failure rather than a lock.
  • Timeout (12s) waiting for privilege escalation prompt — a become problem, not an apt lock.

Frequently Asked Questions

Can I just delete the lock file? Only if you have confirmed no process holds it (lsof/fuser show nothing). Deleting a lock held by a live process can corrupt the package database.

Why does this only happen right after boot? Cloud images run unattended-upgrades and cloud-init on startup, which hold the apt/dpkg locks for the first few minutes. Waiting them out resolves it.

What is the cleanest fix in a playbook? Add until: apt_result is not failed with retries and delay so the task waits for the lock to clear instead of failing on the first attempt.

How do I stop two plays from colliding? Do not run overlapping plays against the same hosts, and consider serial or per-host throttling for package-heavy roles. For more package and provisioning patterns, see the Ansible guides.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.