Ansible Error Guide: 'does not support check mode' — Fix Check-Mode Task Failures
Fix Ansible's 'does not support check mode' error using check_mode false, changed_when, and idempotent modules so --check dry-runs report changes honestly.
- #ansible
- #automation
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
When you run a play with --check, Ansible skips or flags any task whose module cannot simulate its action. Depending on module and version you will see one of these:
fatal: [app01]: FAILED! => {"changed": false, "msg": "remote module (command) does not support check mode"}
Or, more commonly, a skip notice in the output:
skipping: [app01] => (item=...) # module does not support check mode, skipping task
This is not a broken host or a bad argument — it is Ansible telling you that in dry-run mode it cannot safely predict what this task would do, so it refuses to run or skips it rather than pretend.
Symptoms
- Running
ansible-playbook --checkreports a task as failed or skipped with a check-mode message. command,shell,raw, andscripttasks are the usual culprits, since Ansible cannot know what an arbitrary command would do.- A
--checkrun reportschanged=0for a play you know would change things, because change-detecting tasks were skipped. - The play runs fine without
--checkbut cannot be dry-run for review. - A downstream task fails in check mode because a variable it depended on was registered by a skipped task.
Common Root Causes
- Arbitrary-command modules —
command/shell/raw/scripthave no way to simulate side effects, so they do not support check mode by default. - Read-only tasks skipped unnecessarily — a
commandthat only gathers information is skipped in check mode even though it is safe to run. - Custom module without check-mode support — a module written with
supports_check_mode=False. - Registered variable never set — a fact-gathering task skipped in check mode leaves a
registervariable undefined for later tasks. - Expecting a full dry-run from modules that cannot provide one — treating
--checkas a guarantee every task simulates cleanly.
Diagnostic Workflow
Run the play in check mode with diff to see which tasks are skipped versus simulated:
ansible-playbook -i inventory site.yml --check --diff
For a read-only command that is safe to run even in check mode, force it to execute with check_mode: false:
- name: Read current app version (safe in check mode)
ansible.builtin.command: /usr/local/bin/app --version
register: app_version
check_mode: false # this command has no side effects; always run it
changed_when: false # reading a version never counts as a change
For a command that does change state, make its change reporting honest so --check output is meaningful:
- name: Apply migration (mutating command)
ansible.builtin.command: /usr/local/bin/migrate --apply
register: migrate_out
changed_when: "'applied' in migrate_out.stdout"
Verify a custom module’s declared support:
ansible-doc my_namespace.my_collection.my_module | grep -i 'check_mode\|check mode'
Example Root Cause Analysis
A team adopted --check for change-review before every production run. The dry-run reported changed=0 and, trusting it, they promoted the change — which then made dozens of changes when applied for real. Investigating, --check --diff showed the config-detection tasks were all command tasks that check mode had skipped, so nothing downstream ran and the play appeared inert.
The fix reshaped the read-only tasks: every information-gathering command got check_mode: false and changed_when: false so it ran and reported no change in dry-run, and the genuinely mutating commands got accurate changed_when expressions so their potential change showed up in check mode. Where possible, command tasks were replaced with idempotent built-in modules that natively support check mode. After that, a --check run reflected reality and the review step became trustworthy again.
Prevention Best Practices
- Prefer idempotent built-in modules (
copy,template,file,package,service) overcommand/shell; they support check mode natively. - Add
check_mode: falseandchanged_when: falseto read-onlycommandtasks so they run safely and report no change during dry-runs. - Give mutating
commandtasks accuratechanged_whenexpressions so--checkoutput reflects real potential changes. - Set
supports_check_mode=Truein custom modules and honormodule.check_modeinside them. - Do not treat
--checkas a guarantee of full simulation; verify with--check --diffwhich tasks actually run.
Quick Command Reference
# Dry-run with diffs to see what would change
ansible-playbook -i inventory site.yml --check --diff
# Run a single play in check mode
ansible-playbook -i inventory site.yml --check --limit <host>
# Inspect a module's check-mode support
ansible-doc <module> | grep -i 'check'
# Force a safe read-only task to run in check mode (in YAML)
# check_mode: false + changed_when: false
Conclusion
“does not support check mode” means Ansible will not guess what an arbitrary command would do during a dry-run, so it skips or fails the task rather than lie. Make read-only commands run with check_mode: false and changed_when: false, give mutating commands honest change detection, and prefer idempotent modules that simulate natively. Done right, --check becomes a review you can trust instead of a green light that hides real changes.
More Ansible prompts & error guides
Every Ansible AI prompt and troubleshooting guide, in one place.
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.