Fix Ansible "Could not match supplied host pattern" โ€” No Hosts Matched in Inventory

beginner๐Ÿ”ง Ansible2026-03-24| Ansible 2.9+ on Ubuntu 20.04/22.04, CentOS 7/8, macOS โ€” INI and YAML inventory formats

Error Message

[WARNING]: Could not match supplied host pattern, ignoring: webservers [WARNING]: No hosts matched, nothing to do
#ansible#inventory#hosts#pattern#ini

What's Happening

You run a playbook and Ansible prints:

[WARNING]: Could not match supplied host pattern, ignoring: webservers
[WARNING]: No hosts matched, nothing to do

The playbook exits immediately without touching a single task. Ansible found your inventory file โ€” it just couldn't locate the host group or hostname referenced in the playbook's hosts: field.

Almost every time, it's a name mismatch: a typo, the wrong inventory path, or a structural problem in the inventory file. Usually a 2-minute fix once you know where to look.

Debug Process

Step 1 โ€” List what Ansible actually sees in inventory

Start here. Ask Ansible to enumerate every host and group it can parse from your inventory:

# Using a specific inventory file
ansible-inventory -i inventory.ini --list

# Or if you use a directory
ansible-inventory -i inventories/production --list

Scan the JSON output. If webservers (or whatever group you referenced) is absent, Ansible genuinely cannot find it. Either the file itself has a problem, or you're pointing at the wrong file entirely.

Prefer a human-readable tree? Use --graph:

ansible-inventory -i inventory.ini --graph

A healthy group looks like this:

@all:
  |--@webservers:
  |  |--web01.example.com
  |  |--web02.example.com
  |--@ungrouped:

Step 2 โ€” Check what your playbook references

Open your playbook and find the hosts: line:

---
- name: Deploy web app
  hosts: webservers
  tasks:
    ...

That value must exactly match a group name or hostname in inventory. Case-sensitive. No spaces. Go character by character if you have to โ€” a single letter off will cause this error.

Step 3 โ€” Confirm you're pointing at the right inventory file

The single most common cause: running the playbook without -i, so Ansible silently falls back to /etc/ansible/hosts. That file is usually empty, or it doesn't contain your groups.

# Wrong โ€” uses default /etc/ansible/hosts
ansible-playbook deploy.yml

# Correct โ€” explicitly specify your inventory
ansible-playbook -i inventory.ini deploy.yml
ansible-playbook -i inventories/production deploy.yml

To avoid repeating -i on every command, set the path once in ansible.cfg:

[defaults]
inventory = ./inventory.ini

Solution

Fix 1 โ€” Correct the inventory file structure

A valid INI inventory with a [webservers] group looks like this:

[webservers]
web01.example.com
web02.example.com ansible_user=ubuntu

[dbservers]
db01.example.com ansible_user=centos ansible_port=22

Four mistakes that silently break group matching:

  • Extra spaces inside brackets: [ webservers ] โ€” Ansible treats this as a different string, not the group webservers
  • Typo: [webserver] in inventory vs. hosts: webservers in the playbook
  • Hosts listed before their group header โ€” they land in [ungrouped] instead
  • YAML inventory syntax accidentally used inside an .ini file (or vice versa)

Prefer YAML inventory? The equivalent structure:

all:
  children:
    webservers:
      hosts:
        web01.example.com:
        web02.example.com:
          ansible_user: ubuntu
    dbservers:
      hosts:
        db01.example.com:
          ansible_user: centos

Fix 2 โ€” Match the hosts pattern exactly

Update the playbook to use a pattern that actually exists in inventory:

---
- name: Deploy web app
  hosts: webservers     # must match exactly
  become: true
  tasks:
    - name: Install nginx
      apt:
        name: nginx
        state: present

Ansible supports several pattern forms for targeting multiple groups at once:

hosts: all                    # every host in inventory
hosts: webservers,dbservers   # multiple groups
hosts: webservers:&staging    # intersection (webservers AND staging)
hosts: webservers:!dbservers  # webservers but NOT dbservers

Fix 3 โ€” Add inventory path to ansible.cfg

Drop a project-level ansible.cfg next to your playbook and forget about -i forever:

[defaults]
inventory = ./inventory.ini
remote_user = ubuntu
host_key_checking = False

Ansible picks up ansible.cfg from the current directory automatically. Running ansible-playbook deploy.yml without -i will now work correctly.

Verification

Three commands worth running before touching any server:

# Confirm the group now appears
ansible-inventory -i inventory.ini --graph

# Dry-run the playbook (no changes applied)
ansible-playbook -i inventory.ini deploy.yml --check

# List which hosts would be targeted
ansible-playbook -i inventory.ini deploy.yml --list-hosts

A successful --list-hosts run looks like this:

playbook: deploy.yml

  play #1 (webservers): Deploy web app
    pattern: ['webservers']
    hosts (2):
      web01.example.com
      web02.example.com

Still seeing 0 hosts or the warning? Go back to Step 1.

Tips

Complex patterns like webservers:&production:!disabled are easy to get wrong, especially with larger inventories. Before putting a pattern in a playbook, I verify the logic with the Regex Tester on ToolCraft โ€” paste your host list, test whether the pattern matches what you expect. It runs entirely in the browser with no data uploaded, which matters when your list contains internal server names.

Lessons Learned

  • Always pass -i explicitly when running from outside a project directory, or configure ansible.cfg so inventory is always resolved correctly.
  • Run ansible-inventory --graph first whenever a playbook behaves unexpectedly โ€” it shows exactly what Ansible parsed, not what you think you wrote.
  • INI group headers are whitespace-sensitive โ€” [webservers] and [ webservers ] are different strings as far as Ansible is concerned.
  • Use --list-hosts before every significant run โ€” a safe, read-only check that confirms your targeting before any task touches a real server.

Related Error Notes