Default Rules

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

command-instead-of-module

Using command rather than module.

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

command-instead-of-shell

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!)

deprecated-bare-vars

This rule identifies possible confusing expressions where it is not clear if a variable or string is to be used and asks for clarification.

You should either use the full variable syntax (‘{{{{ {0} }}}}’) or, whenever possible, convert it to a list of strings.

Problematic code

---
- ansible.builtin.debug:
    msg: "{{ item }}"
  with_items: foo # <-- deprecated-bare-vars

Correct code

---
# if foo is not really a variable:
- ansible.builtin.debug:
    msg: "{{ item }}"
  with_items:
    - foo

# if foo is a variable:
- ansible.builtin.debug:
    msg: "{{ item }}"
  with_items: "{{ foo }}"

deprecated-command-syntax

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

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

deprecated-local-action

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

Do not use local_action, use delegate_to: localhost

deprecated-module

Deprecated module.

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

fqcn-builtins

Use FQCN for builtin actions.

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

git-latest

Git checkouts must contain explicit version.

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

hg-latest

Mercurial checkouts must contain explicit revision.

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

ignore-errors

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.

inline-env-var

Command module does not accept setting environment variables inline.

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

internal-error

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.

key-order

Ensure specific order of keys in mappings.

literal-compare

Don’t compare to literal True/False.

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

load-failure

Linter failed to process a YAML file, probably because it is either:

  • contains unsupported encoding (only UTF-8 is supported)

  • not an Ansible file

  • it contains some unsupported custom YAML objects (!! prefix)

  • it was not able to decrypt an inline !vault block.

This violation is not skippable, so it cannot be added to the warn_list or the skip_list. If a vault decryption issue cannot be avoided, the offending file can be added to exclude_paths configuration.

meta-incorrect

meta/main.yml default values should be changed.

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

meta-no-info

meta/main.yml should contain relevant info.

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

meta-no-tags

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

no-changed-when

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
      ansible.builtin.shell: cat {{ my_file|quote }}
      register: my_output
      changed_when: my_output.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 {{ my_file|quote }}

no-handler

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

no-jinja-nesting

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-jinja-when

No Jinja2 in when.

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

no-loop-var-prefix

Role loop_var should use configured prefix.

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

no-relative-paths

Doesn’t need a relative path in role.

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

no-tabs

Most files should not contain tabs.

Tabs can cause unexpected display issues, use spaces

package-latest

Package installs should not use latest.

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

parser-error

AnsibleParserError.

Ansible parser fails; this usually indicates an invalid file.

partial-become

become_user requires become to work as expected.

become_user without become will not actually change user

playbook-extension

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

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

risky-file-permissions

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. more

risky-octal

Octal file permissions must contain leading zero or be a string.

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

risky-shell-pipe

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

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

Role names are now limited to contain only lowercase alphanumeric characters, plus underline and start with an alpha character. more

schema

Perform JSON Schema Validation for known lintable kinds.

Returned errors will not include exact line numbers, but they will mention the schema name being used as a tag, like playbook-schema, tasks-schema.

This rule is not skippable and stops further processing of the file.

Schema bugs should be reported towards schemas project instead of ansible-lint.

If incorrect schema was picked, you might want to either:

  • move the file to standard location, so its file is detected correctly.

  • use kinds: option in linter config to help it pick correct file type.

syntax-check

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.

unnamed-task

All tasks should be named.

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

var-naming

All variables should be named using only lowercase and underscores.

var-spacing

Variables and filters in Jinja2 should have spaces before and after, like {{ var_name | filter }}.. This improves readability and makes it less likely to introduce typos.

Problematic code

---
foo: "{{some|dict2items}}"

Correct code

---
foo: "{{ some | dict2items }}"

yaml

Our linter also includes violations reported by yamllint but it uses a slightly different default configuration. We will still load custom yamllint configuration files, but the defaults come from ansible-lint, not from yamllint.

You can fully disable all yamllint violations by adding yaml to the skip_list.

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

Problematic code

# missing document-start
foo: ...
foo: ...  # <-- key-duplicates
bar: ...       # <-- wrong comment indentation

Correct code

---
foo: ...
bar: ... # comment