Fix Ansible 'this task has extra params' Error: Free-Form Module Syntax Mistake

beginner๐Ÿ”ง Ansible2026-05-05| Ansible 2.x and later, any OS running ansible-playbook (Ubuntu, CentOS, macOS)

Error Message

ERROR! this task 'copy' has extra params, which is only allowed in the following modules: raw, meta, include, include_tasks, import_tasks
#ansible#module#syntax#free-form#params#playbook

The Error

ERROR! this task 'copy' has extra params, which is only allowed in the following modules: raw, meta, include, include_tasks, import_tasks

Run ansible-playbook and it bails immediately โ€” no connection attempt, no host output, nothing. The fault is in the task definition itself, not on the remote host.

What Triggers This

Ansible modules accept arguments two ways:

  • Free-form (inline string): only valid for command, shell, raw, script. One string, same line as the module key.
  • Key=value or YAML dict: everything else โ€” copy, file, apt, template, and so on.

The error triggers when you mix these styles. Usually that means parameters are placed at the task level instead of nested under the module, or an inline string is combined with YAML keys in the same task block. One misplaced argument is enough.

Common Scenarios That Cause It

Scenario 1: Extra key placed at task level instead of module level

# WRONG
- name: Copy config file
  copy: src=files/app.conf dest=/etc/app/app.conf
  mode: '0644'         # <-- task level, not under copy:
  owner: root

mode and owner land on the task dict rather than inside the module. Ansible treats them as unknown task-level keys and throws the error.

Scenario 2: Free-form string mixed with YAML dict keys

# WRONG
- name: Copy config file
  copy: src=files/app.conf dest=/etc/app/app.conf
    mode: '0644'

Mixing an inline key=value string with indented YAML under the same module key breaks the parser. Pick one style and stick with it.

Scenario 3: Typo โ€” second module key left in the task block

# WRONG
- name: Restart nginx
  service:
    name: nginx
    state: restarted
  copy:                  # <-- leftover from a cut-paste
    src: files/nginx.conf
    dest: /etc/nginx/nginx.conf

A task can only have one module. The second module key (copy: here) becomes an unrecognized extra param โ€” classic copy-paste artifact.

The Fix

Nest all arguments under the module with YAML dict syntax

# CORRECT
- name: Copy config file
  copy:
    src: files/app.conf
    dest: /etc/app/app.conf
    mode: '0644'
    owner: root

Every argument goes under copy: as an indented key. At the same indentation level as copy:, only standard task keywords belong: name, when, notify, tags, become, and so on.

Inline key=value also works โ€” but keep it all on one line

# CORRECT โ€” all args inline
- name: Copy config file
  copy: src=files/app.conf dest=/etc/app/app.conf mode='0644' owner=root

Past three or four arguments this becomes a wall of text. YAML dict form is easier to read and review in pull requests.

Free-form modules (command, shell) work differently

# CORRECT โ€” shell/command use free-form
- name: Check disk usage
  shell: df -h /

# CORRECT โ€” structured options go under args:, not mixed inline
- name: Run script with timeout
  command: /opt/scripts/deploy.sh
  args:
    chdir: /opt/scripts

Even with free-form modules, structured options like chdir or stdin go under args:. Never inline them alongside the command string.

Quick Diagnostic

Ansible names the offending task in the error message. Find that task in your playbook and scan for:

  • Any key at the task's top level that is not a standard Ansible keyword (name, when, register, loop, notify, tags, become, ignore_errors, etc.)
  • Module arguments sitting one indentation level too high
  • Two module keys in the same task block

Before touching any remote host, run a syntax check:

ansible-playbook site.yml --syntax-check

No SSH connections, no risk โ€” just a fast parse of your YAML.

Verify the Fix

# Syntax check โ€” should return no errors
ansible-playbook site.yml --syntax-check

# Expected output
playbook: site.yml

# Dry run to confirm task would execute correctly
ansible-playbook site.yml --check --diff

A clean --syntax-check exit means the extra params error is gone. Follow it with --check --diff to see exactly what the task would change โ€” still without touching the remote host.

Tips to Avoid This in the Future

  • Default to YAML dict syntax for non-free-form modules. It makes indentation errors obvious at a glance.
  • Add --syntax-check to your CI pipeline. It catches this entire class of error in under a second, before the PR merges.
  • Run ansible-lint locally. Install it with pip install ansible-lint, then run ansible-lint site.yml. It flags mixed syntax and dozens of other style issues.
  • Install the VS Code Ansible extension (Red Hat). Structural errors show up as red squiggles while you type โ€” no need to run anything.

Related Error Notes