Default Rules

Below you can see the list of default rules Ansible Lint use to evaluate playbooks and roles:


Using command rather than module

Executing a command when there is an Ansible module is generally a bad idea


Use shell only when shell functionality is required

Shell should only be used when piping, redirecting or chaining commands (and Ansible would be preferred for some of those!)


Using bare variables is deprecated

Using bare variables is deprecated. Update your playbooks so that the environment value uses the full variable syntax {{ your_variable }}


Using command rather than an argument to e.g. file

Executing a command when there are arguments to modules is generally a bad idea


Do not use ‘local_action’, use ‘delegate_to: localhost’

Do not use local_action, use delegate_to: localhost


Deprecated module

These are deprecated modules, some modules are kept temporarily for backwards compatibility but usage is discouraged. For more details see:


Don’t compare to empty string

Use when: var|length > 0 rather than when: var != "" (or conversely when: var|length == 0 rather than when: var == "")


Use FQCN for builtin actions

Check whether the long version starting with ansible.builtin is used in the playbook


Git checkouts must contain explicit version

All version control checkouts must point to an explicit commit or tag, not just latest


Mercurial checkouts must contain explicit revision

All version control checkouts must point to an explicit commit or tag, not just latest


Use failed_when and specify error conditions instead of using ignore_errors

Instead of ignoring all errors, ignore the errors only when using {{ ansible_check_mode }}, register the errors using register, or use failed_when: and specify acceptable error conditions to reduce the risk of ignoring important failures.


Command module does not accept setting environment variables inline

Use environment: to set environment variables or use shell module which accepts both


Unexpected internal error

This error can be caused by internal bugs but also by custom rules. Instead of just stopping linter we generate the errors and continue processing. This allows users to add this rule to their warn list until the root cause is fixed.


Don’t compare to literal True/False

Use when: var rather than when: var == True (or conversely when: not var)


Failed to load or parse file

Linter failed to process a YAML file, possible not an Ansible file.


meta/main.yml default values should be changed

meta/main.yml default values should be changed for: author, description, company, license, license


meta/main.yml should contain relevant info

meta/main.yml should contain: author, description, license, min_ansible_version, platforms


Tags must contain lowercase letters and digits only

Tags must contain lowercase letters and digits only, and galaxy_tags is expected to be a list


Commands should not change things if nothing needs doing

Tasks should tell Ansible when to return changed, unless the task only reads information. To do this, set changed_when, use the creates or removes argument, or use when to run the task only if another check has a particular result.

For example, this task registers the shell output and uses the return code to define when the task has changed.

- name: handle shell output with return code cat {{ myfile|quote }}
  register: myoutput
  changed_when: myoutput.rc != 0

The following example will trigger the rule since the task does not handle the output of the command.

- name: does not handle any output or return codes
  ansible.builtin.command: cat {{ myfile|quote }}


Tasks that run when changed should likely be handlers

If a task has a when: result.changed setting, it is effectively acting as a handler. You could use notify and move that task to handlers. (more)


Nested jinja pattern

There should not be any nested jinja pattern. Example (bad): {{ list_one + {{ list_two | max }} }}, Example (good): {{ list_one + max(list_two) }}, Example (allowed): --format='{{'{{'}}.Size{{'}}'}}'


No Jinja2 in when

when is a raw Jinja2 expression, remove redundant {{ }} from variable(s).


password should not be logged.

When passing password argument you should have no_log configured to a non False value to avoid accidental leaking of secrets.


Role loop_var should use configured prefix.

Looping inside roles has the risk of clashing with loops from user-playbooks. (more)


Doesn’t need a relative path in role

copy and template do not need to use relative path for src


Owner should not be kept between different hosts

Optional rule that highlights dangers of assuming that user/group on the remote machines may not exist on ansible controller or vice versa. Owner and group should not be preserved when transferring files between them.

This rule is not enabled by default and was inspired by Zuul execution policy. See:


Most files should not contain tabs

Tabs can cause unexpected display issues, use spaces


Package installs should not use latest

Package installs should use state=present with or without a version



Ansible parser fails; this usually indicates an invalid file.


become_user requires become to work as expected

become_user without become will not actually change user


Use “.yml” or “.yaml” playbook extension

Playbooks should have the “.yml” or “.yaml” extension


File permissions unset or incorrect

Missing or unsupported mode parameter can cause unexpected file permissions based on version of Ansible being used. Be explicit, like mode: 0644 to avoid hitting this rule. Special preserve value is accepted only by copy, template modules. See


Octal file permissions must contain leading zero or be a string

Numeric file permissions without leading zero can behave in unexpected ways. See


Shells that use pipes should set the pipefail option

Without the pipefail option set, a shell command that implements a pipeline can fail and still return 0. If any part of the pipeline other than the terminal command fails, the whole pipeline will still return 0, which may be considered a success by Ansible. Pipefail is available in the bash shell.


Role name {0} does not match ^[a-z][a-z0-9_]+$ pattern

Role names are now limited to contain only lowercase alphanumeric characters, plus ‘_’ and start with an alpha character. See developing collections


Ansible syntax check failed

Running ansible-playbook --syntax-check ... failed.

This error cannot be disabled due to being a prerequisite for other steps. You can either exclude these files from linting or better assure they can be loaded by Ansible. This is often achieved by editing inventory file and/or ansible.cfg so ansible can load required variables.

If undefined variables are the failure reason you could use jinja default() filter in order to provide fallback values.


All tasks should be named

All tasks should have a distinct name for readability and for --start-at-task to work


All variables should be named using only lowercase and underscores

All variables should be named using only lowercase and underscores


Variables should have spaces before and after: {{ var_name }}

Variables should have spaces before and after: {{ var_name }}


Violations reported by yamllint

Rule violations reported by YamlLint when this is installed.

You can fully disable all of them by adding ‘yaml’ to the ‘skip_list’.

Specific tag identifiers that are printed at the end of rule name, like ‘trailing-spaces’ or ‘indentation’ can also be be skipped, allowing you to have a more fine control.

By default this rule is not used when yamllint library is missing. If you want to make its absence a runtime failure, please add ‘yaml’ to ‘enable_list’ inside the configuration file.