Ansibleタスクの「ERROR! conflicting action statements: copy, template」を修正する

beginner🔧 Ansible2026-05-16| Ansible 2.x以降、任意のOS(Linux/macOS)、任意のPlaybook

Error Message

ERROR! conflicting action statements: copy, template
#タスク#モジュール#構文#Playbook

エラーの内容

プレイブックの実行中に処理が止まります:

ERROR! conflicting action statements: copy, template

タスクの内容によっては、次のようなバリエーションも発生します:

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

モジュール名は異なりますが、根本原因は常に同じです。1つのタスクブロックが同時に2つのアクションモジュールを実行しようとしています。

なぜこのエラーが発生するのか

Ansibleには厳格なルールがあります。1つのタスクにはアクションモジュールを1つだけ、これが絶対です。パーサーが同じインデントレベルに2つのモジュールキーを検出した場合、どちらを優先すべきか判断する方法がありません。そのため、推測せずに処理を停止します。

ほとんどの場合、このエラーはコピー&ペーストの際に忍び込みます。2つのタスクブロックをマージしたとき、重複したキーが一緒についてきたことに気づかないのです:

- 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

ここでは copytemplate が同じ階層に存在しています。Ansibleは conflicting action statements: copy, template を発生させ、それ以上の処理を拒否します。

手順ごとの修正方法

ステップ1 — 問題のあるタスクを見つける

Ansibleのエラー出力は実際にかなり役立ちます。競合するモジュール名を示し、どこを確認すればよいかを正確に教えてくれます:

ERROR! conflicting action statements: copy, template

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

ファイルを開いて14行目に移動してください。問題のあるタスクがそこにあります。

ステップ2 — 適切なモジュールを選択する

削除する前に、どちらのモジュールが本来必要なのかを判断してください。最もよくある競合パターンの早見表を示します:

  • copy vs template — 変数を含まない静的ファイルなら copy を使います。{{ db_host }} のようなJinja2式が含まれるなら template を使います。
  • apt vs yum — 対象OSに合ったパッケージマネージャーを選ぶか、汎用の package モジュールを使って議論を回避しましょう。
  • file vs copy — 既存パスのパーミッション、オーナーシップ、またはシンボリックリンクを管理するなら file です。コントロールノードからリモートにファイルを転送するなら copy です。

ステップ3 — 分割するか削除する

方法A:一方のモジュールを残し、もう一方を削除する

# Before (broken)
- 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

# After (fixed) — 実際に必要な方を選択する
- name: Deploy config file
  template:
    src: templates/app.conf.j2
    dest: /etc/app/app.conf
    owner: root
    group: root
    mode: '0644'

方法B:両方のアクションが本当に必要な場合は、2つのタスクに分割する

- 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'

ステップ4 — YAMLアンカーによる隠れた競合を探す

問題のある行が一見わかりにくい場合もあります。YAMLアンカーがアクションキーを持つブロックを展開し、重複を見えにくくすることがあります:

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

- name: Deploy config
  <<: *defaults
  template:           # conflict — 'copy' merged in from the anchor above
    src: templates/app.conf.j2
    dest: /etc/app/app.conf

アンカーをインラインで展開するか、マージによって競合するモジュールキーが取り込まれないようにタスクを再構成してください。

修正を確認する

プレイブック全体をそのまま実行しないでください。まず構文チェックから始めましょう。コストはゼロで、どのホストにも触れる前に問題を検出できます:

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

成功すると次のように表示されます。プレイブック名だけで、それ以外は何もありません:

playbook: site.yml

問題ありません。次に実際のホストに対してドライランを実行し、何が変更されるかを確認します:

ansible-playbook site.yml --check -v

出力に問題がなければ、実際に実行します:

ansible-playbook site.yml

クイックリファレンス:1タスク1モジュールの原則

有効なタスクにはアクションモジュールが1つだけあります。それ以外の becomewhennotifyregisterlooptags はタスクディレクティブです。これらはモジュールと並列に配置され、競合しません:

- name: Descriptive name of what this task does
  module_name:          # exactly ONE action module
    param1: value1
    param2: value2
  become: true          # task directive — fine to have alongside the module
  when: some_condition
  notify: restart app

同じレベルに2つのアクションモジュール?それは絶対に許されません。覚えておくべきルールはこれだけです。

今後の予防策

  • プレイブックを実行するたびに yamllint を実行しましょう。Ansibleがファイルを読み込む前に重複キーを検出します。
  • ansible-lint にはモジュールの競合使用に特化したルールがあります。CIパイプラインに追加する価値があります。
  • ロールのタスクをマージしたり、プレイブック間でコピー&ペーストした後は素早くスキャンしてください。各タスクブロックにはモジュールキーが1つだけあるべきです。
  • VS Code用のAnsible拡張機能は、入力中に競合するキーをハイライト表示し、問題を発生源で検出できます。

Related Error Notes