Introduction

Error 205 (playbook-extension) is an ansible-lint rule that flags playbook files using incorrect file extensions. While Ansible itself accepts multiple extensions, following consistent naming conventions improves project organization and enables proper tooling integration.

The Error

When running ansible-lint, you may see:

WARNING  Listing 1 violation(s) that are fatal
playbook-extension: Use ".yml" or ".yaml" playbook extension.
deploy.YML:1

Or in newer versions:

deploy.play (playbook-extension)
Playbooks should have the ".yml" or ".yaml" extension.

Root Cause

The ansible-lint rule playbook-extension enforces that all playbook files use one of the standard YAML extensions:

  • .yml (preferred)
  • .yaml (acceptable)

Files that trigger this error may have:

  • Uppercase extensions: .YML, .YAML
  • No extension at all: deploy (no .yml)
  • Non-standard extensions: .ansible, .playbook
  • Mixed case: .Yml

The Fix

# Fix uppercase extension
mv deploy.YML deploy.yml

# Fix missing extension
mv deploy deploy.yml

# Fix non-standard extension
mv deploy.ansible deploy.yml

Option 2: Configure ansible-lint to Accept Your Convention

If your organization uses .yaml instead of .yml, both are valid. But if you want to suppress the rule entirely:

.ansible-lint:

---
skip_list:
  - playbook-extension  # Allow any extension

Or to warn instead of error:

---
warn_list:
  - playbook-extension

Best Practices for File Extensions

Standard Convention

File TypeRecommended ExtensionExample
Playbooks.ymldeploy.yml, site.yml
Roles tasks.ymltasks/main.yml
Variable files.ymlvars/main.yml
Inventory (YAML).ymlinventory.yml
Inventory (INI).ini or no extensioninventory
Requirements.ymlrequirements.yml

File Naming Conventions

project/
├── site.yml              # Main playbook
├── webservers.yml        # Host-specific playbook
├── deploy-app.yml        # Task-specific playbook
├── inventory/
│   ├── production.yml
│   └── staging.yml
├── roles/
│   └── nginx/
│       ├── tasks/
│       │   └── main.yml
│       ├── handlers/
│       │   └── main.yml
│       ├── templates/
│       │   └── nginx.conf.j2
│       └── vars/
│           └── main.yml
└── group_vars/
    ├── all.yml
    └── webservers.yml

Why .yml Over .yaml?

Both work identically, but .yml is the Ansible community standard:

  • Official Ansible documentation uses .yml
  • ansible-galaxy init generates .yml files
  • Most online examples use .yml
  • Shorter (saves 1 character in hundreds of files)

Choose one and stick with it project-wide for consistency.

Configuring ansible-lint

Full .ansible-lint Configuration

---
# .ansible-lint
profile: production  # or: min, basic, moderate, safety, shared

# Rules to skip entirely
skip_list:
  - yaml[line-length]  # Allow long lines

# Rules that warn instead of fail
warn_list:
  - experimental       # Experimental rules

# Exclude paths from linting
exclude_paths:
  - .github/
  - collections/
  - molecule/

# File extensions to look for
kinds:
  - playbook: "**/playbooks/*.yml"
  - tasks: "**/tasks/*.yml"
  - vars: "**/vars/*.yml"
  - meta: "**/meta/*.yml"

Running ansible-lint

# Lint all playbooks in current directory
ansible-lint

# Lint a specific file
ansible-lint deploy.yml

# Lint with specific profile
ansible-lint -p moderate

# List all rules
ansible-lint -L

# Show rule details
ansible-lint -R -r playbook-extension
RuleIDDescription
playbook-extension205Wrong file extension
yaml[truthy]—Use true/false not yes/no
name[missing]—Tasks should have names
fqcn[action-core]—Use fully qualified module names
no-changed-when—Commands need changed_when
risky-shell-pipe—Shell pipes may hide errors

Complete Example: Correct Project Structure

# site.yml (correct extension, lowercase)
---
- name: Deploy web application
  hosts: webservers
  become: true
  roles:
    - nginx
    - app

- name: Configure database
  hosts: dbservers
  become: true
  roles:
    - postgresql
# Run lint to verify
$ ansible-lint site.yml
Passed: 0 failure(s), 0 warning(s)

Bulk Rename Script

If you have many files to fix:

#!/bin/bash
# Fix all uppercase .YML extensions
find . -name "*.YML" -exec bash -c 'mv "$0" "${0%.YML}.yml"' {} \;

# Fix all .YAML extensions
find . -name "*.YAML" -exec bash -c 'mv "$0" "${0%.YAML}.yml"' {} \;

# Fix .yaml to .yml (optional, for consistency)
find . -name "*.yaml" -exec bash -c 'mv "$0" "${0%.yaml}.yml"' {} \;

Conclusion

Error 205 (playbook-extension) is a simple naming convention issue. Rename your playbook files to use .yml (lowercase), which is the Ansible community standard. Configure .ansible-lint in your project root to set your team's linting standards and ensure consistency across all contributors.