Ansible Conflicting Action Statements Error: Causes and Fixes
By Luca Berton · Published 2024-01-01 · Category: installation
Fix the Ansible 'conflicting action statements' error with real examples. Covers duplicate module names, free-form vs YAML syntax mixing, action/local_action.
"Conflicting action statements" means Ansible found two or more module calls in the same task. A task can only have one action — this error tells you something is structurally wrong.
The Error
ERROR! conflicting action statements: ansible.builtin.copy, ansible.builtin.template
The error appears to be in '/path/to/playbook.yml': line 5, column 7
See also: Ansible Troubleshooting Installation Issues on macOS and Python
Cause 1: Two Modules in One Task
The most common cause — accidentally putting two modules in the same task:
# ❌ TWO MODULES in one task
- name: Deploy config
ansible.builtin.copy:
src: config.conf
dest: /etc/myapp/
ansible.builtin.template:
src: config.j2
dest: /etc/myapp/config.conf
# ✅ FIX: Split into two tasks
- name: Copy static file
ansible.builtin.copy:
src: config.conf
dest: /etc/myapp/
- name: Deploy template
ansible.builtin.template:
src: config.j2
dest: /etc/myapp/config.conf
Cause 2: Free-Form and YAML Syntax Mixed
# ❌ free-form (key: value on same line) + YAML args
- name: Install package
ansible.builtin.apt: name=nginx
state: present # This is indented under apt, making it a second statement
# ✅ FIX: Use one syntax
- name: Install package
ansible.builtin.apt:
name: nginx
state: present
# Or free-form (not recommended):
- name: Install package
ansible.builtin.apt: name=nginx state=present
See also: Ansible Permission Denied on Remote Temp Path: Fix Every Cause
Cause 3: action + Module Name
# ❌ Both action: and module name
- name: Copy file
action: ansible.builtin.copy
ansible.builtin.copy:
src: file.txt
dest: /tmp/
# ✅ FIX: Use one or the other
- name: Copy file
ansible.builtin.copy:
src: file.txt
dest: /tmp/
Cause 4: local_action + Module
# ❌ Both local_action and module
- name: Check URL
local_action: ansible.builtin.uri url=http://localhost
ansible.builtin.uri:
url: http://localhost
# ✅ FIX: Use delegate_to instead
- name: Check URL
ansible.builtin.uri:
url: http://localhost
delegate_to: localhost
See also: Ansible Template Error While Templating String: Fix Every Jinja2 Error
Cause 5: YAML Indentation Error
# ❌ Bad indentation makes Ansible parse two modules
- name: Deploy app
ansible.builtin.copy:
src: app.tar.gz
dest: /opt/app/
ansible.builtin.unarchive: # Same indentation as copy = same task
src: /opt/app/app.tar.gz
dest: /opt/app/
# ✅ FIX: Make it two tasks (- at start)
- name: Upload archive
ansible.builtin.copy:
src: app.tar.gz
dest: /opt/app/
- name: Extract archive
ansible.builtin.unarchive:
src: /opt/app/app.tar.gz
dest: /opt/app/
remote_src: true
Cause 6: Role Parameters That Look Like Modules
# ❌ Incorrect role include syntax
- name: Run role
include_role:
name: nginx
ansible.builtin.debug: # This looks like a second action
msg: "Done"
# ✅ FIX: Separate tasks
- name: Run role
ansible.builtin.include_role:
name: nginx
- name: Report done
ansible.builtin.debug:
msg: "Done"
Cause 7: Copy-Paste Errors
# ❌ Forgot to add the dash for new task
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
name: Start nginx # No dash = still same task
ansible.builtin.systemd:
name: nginx
state: started
# ✅ FIX: Add the dash
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
- name: Start nginx
ansible.builtin.systemd:
name: nginx
state: started
Prevention
Use ansible-lint
ansible-lint playbook.yml
# Catches conflicting actions before you run the playbook
Use YAML Syntax Only
# ✅ Always use YAML syntax (not free-form)
- ansible.builtin.apt:
name: nginx
state: present
# ❌ Avoid free-form (harder to read, easier to break)
- ansible.builtin.apt: name=nginx state=present
Use an Editor with YAML Validation
VS Code with the Ansible extension highlights structural issues in real-time.
FAQ
Why does Ansible allow only one module per task?
Each task is a single unit of work — it runs one module on one or more hosts. Multiple modules in one task would create ambiguity about execution order, error handling, and change tracking.
How do I run multiple commands in one task?
Use the shell module with a multiline script, or better, create separate tasks for each action. For complex orchestration, use block: to group related tasks.
Does ansible-lint catch this error?
Yes. ansible-lint catches conflicting action statements and many other structural issues before you run the playbook. Run ansible-lint as part of your CI/CD pipeline.
Conclusion
"Conflicting action statements" always means one thing: two modules in one task. The fix is always the same: split them into separate tasks. Use ansible-lint and YAML validation in your editor to catch these before runtime.
Related Articles
• Ansible Playbook Structure Guide • Ansible Lint: Analyze & Fix Playbooks • Ansible Template Error: Fix Jinja2 Errors • YAML Multiline Strings in AnsibleCategory: installation