Sửa lỗi 'ERROR! conflicting action statements: copy, template' trong Ansible Tasks

beginner🔧 Ansible2026-05-16| Ansible 2.x trở lên, mọi hệ điều hành (Linux/macOS), mọi playbook

Error Message

ERROR! conflicting action statements: copy, template
#task#module#cú pháp#playbook

Lỗi Gặp Phải

Playbook của bạn bị dừng giữa chừng:

ERROR! conflicting action statements: copy, template

Hoặc các biến thể khác tùy thuộc vào nội dung task của bạn:

ERROR! conflicting action statements: apt, yum
ERROR! conflicting action statements: file, copy

Tên module có thể khác nhau, nhưng nguyên nhân gốc rễ thì không bao giờ thay đổi: một task block đang cố chạy hai action module cùng một lúc.

Tại Sao Lỗi Này Xảy Ra

Ansible áp dụng một quy tắc nghiêm ngặt — mỗi task chỉ được có một action module, không có ngoại lệ. Khi parser gặp hai module key nằm cùng cấp thụt lề, nó không có cách nào quyết định cái nào được ưu tiên. Vì vậy nó không đoán mò — nó dừng lại.

Chín trong mười trường hợp, lỗi này xuất hiện do copy-paste. Bạn gộp hai task block lại và không để ý có một key bị trùng lặp theo vào:

- name: Deploy config file
  copy:
    src: files/app.conf
    dest: /etc/app/app.conf
  template:
    src: templates/app.conf.j2
    dest: /etc/app/app.conf

Cả copytemplate đều nằm ngang hàng nhau ở đây. Ansible báo lỗi conflicting action statements: copy, template và từ chối tiếp tục.

Cách Sửa Từng Bước

Bước 1 — Tìm task bị lỗi

Thông báo lỗi của Ansible thực ra khá hữu ích. Nó chỉ rõ các module xung đột và cho bạn biết chính xác nơi cần xem:

ERROR! conflicting action statements: copy, template

The error appears to be in '/home/deploy/playbooks/site.yml': line 14, column 5

Mở file đó. Nhảy đến dòng 14. Task bị lỗi sẽ hiện ra ngay tại đó.

Bước 2 — Chọn đúng module cần dùng

Trước khi xóa bất cứ thứ gì, hãy xác định module nào thực sự phù hợp. Đây là bảng tóm tắt nhanh cho các xung đột phổ biến nhất:

  • copy vs template — File tĩnh không có biến? Dùng copy. File có biểu thức Jinja2 như {{ db_host }}? Dùng template.
  • apt vs yum — Chọn package manager phù hợp với hệ điều hành đích, hoặc tránh tranh luận bằng cách dùng module package chung.
  • file vs copy — Quản lý quyền, ownership, hoặc symlink trên đường dẫn đã tồn tại? Đó là file. Đẩy file từ control node lên remote? Đó là copy.

Bước 3 — Tách ra hoặc cắt bỏ

Phương án A: Giữ một module, bỏ module kia

# Trước (bị lỗi)
- name: Deploy config file
  copy:
    src: files/app.conf
    dest: /etc/app/app.conf
  template:
    src: templates/app.conf.j2
    dest: /etc/app/app.conf

# Sau (đã sửa) — chọn cái bạn thực sự cần
- name: Deploy config file
  template:
    src: templates/app.conf.j2
    dest: /etc/app/app.conf
    owner: root
    group: root
    mode: '0644'

Phương án B: Cả hai action đều thực sự cần thiết — tách thành hai task riêng biệt

- name: Copy static base config
  copy:
    src: files/base.conf
    dest: /etc/app/base.conf
    mode: '0644'

- name: Render dynamic app config
  template:
    src: templates/app.conf.j2
    dest: /etc/app/app.conf
    mode: '0644'

Bước 4 — Tìm xung đột ẩn từ YAML anchors

Đôi khi dòng lỗi không rõ ràng. YAML anchor có thể mở rộng một block đã chứa sẵn action key, khiến key trùng lặp bị chôn vùi bên trong:

defaults: &defaults
  copy:
    src: files/default.conf
    dest: /etc/app/default.conf

- name: Deploy config
  <<: *defaults
  template:           # xung đột — 'copy' được merge vào từ anchor ở trên
    src: templates/app.conf.j2
    dest: /etc/app/app.conf

Hãy khai triển anchor trực tiếp hoặc cấu trúc lại các task để việc merge không kéo theo module key cạnh tranh.

Xác Nhận Bản Sửa

Đừng chạy toàn bộ playbook mà không kiểm tra trước. Hãy bắt đầu bằng lệnh kiểm tra cú pháp — nó không tốn kém gì và phát hiện vấn đề trước khi bất kỳ host nào bị tác động:

ansible-playbook site.yml --check --syntax-check

Thành công trông như thế này — chỉ có tên playbook, không có gì khác:

playbook: site.yml

Tốt. Bây giờ hãy chạy thử trên các host thực để xem những gì sẽ thay đổi:

ansible-playbook site.yml --check -v

Hài lòng với kết quả? Chạy thật:

ansible-playbook site.yml

Tóm Tắt Nhanh: Một Module Cho Mỗi Task

Một task hợp lệ có đúng một action module. Tất cả những thứ còn lại — become, when, notify, register, loop, tags — là các task directive. Chúng đứng bên cạnh module và không xung đột với nó:

- name: Tên mô tả rõ ràng task này làm gì
  module_name:          # đúng MỘT action module
    param1: value1
    param2: value2
  become: true          # task directive — hoàn toàn hợp lệ khi đứng cạnh module
  when: some_condition
  notify: restart app

Hai action module cùng cấp? Không bao giờ. Đó là quy tắc duy nhất bạn cần ghi nhớ.

Phòng Ngừa Lỗi Về Sau

  • Chạy yamllint trước mỗi lần chạy playbook — nó phát hiện key trùng lặp trước khi Ansible thậm chí nhìn thấy file.
  • ansible-lint có quy tắc chuyên dụng để phát hiện xung đột module. Đáng để thêm vào CI pipeline của bạn.
  • Sau khi gộp role task hoặc copy-paste giữa các playbook, hãy kiểm tra nhanh: mỗi task block phải có đúng một module key.
  • Extension Ansible cho VS Code tô sáng các key xung đột ngay khi bạn gõ, giúp phát hiện vấn đề từ nguồn gốc.

Related Error Notes