You run ansible-playbook site.yml --check to preview changes, and it fails. Check mode (dry run) should let you see what would happen without actually changing anything, but not all tasks support it, and some failures are specific to check mode.
Understanding the Error
Check mode failures appear differently:
fatal: [webserver01]: FAILED! => {"msg": "check mode not supported for this module"}Or:
fatal: [webserver01]: FAILED! => {"msg": "Cannot run command in check mode"}Or more subtly - tasks report changes that wouldn't actually happen, or fail when they would succeed in normal mode.
Step 1: Identify Check Mode Incompatible Tasks
Some modules don't support check mode:
ansible-playbook site.yml --check --diff -vLook for tasks that fail:
TASK [Run script] ***********************************************************
fatal: [webserver01]: FAILED! => {"msg": "check mode not supported for command module"}Modules that typically don't support check mode:
- command / shell - arbitrary commands can't be simulated
- script - running scripts can't be previewed
- Some custom modules
Mark tasks that don't support check mode:
- name: Run destructive script
command: /opt/app/migrate.sh
check_mode: no # Always run, even in check modeOr skip in check mode:
- name: Run script
command: /opt/app/migrate.sh
when: not ansible_check_mode # Skip in check modeStep 2: Handle Command/Shell in Check Mode
Command and shell modules need special handling:
```yaml # WRONG - fails in check mode - name: Create directory command: mkdir -p /opt/app
# CORRECT - use file module which supports check - name: Create directory file: path: /opt/app state: directory ```
If you must use command/shell:
```yaml - name: Run script command: /opt/app/setup.sh check_mode: no # Run even in check mode
- name: Preview script output
- command: /opt/app/setup.sh --dry-run
- when: ansible_check_mode
`
Step 3: Force Tasks in Check Mode
Some tasks should always run even in check mode:
```yaml - name: Gather facts if missing setup: check_mode: no # Must run to get facts
- name: Read current state
- slurp:
- src: /etc/app/config.yml
- register: current_config
- check_mode: no # Must read actual file
`
Step 4: Handle Changes Reported in Check Mode
Check mode reports what would change, but estimates can be wrong:
- name: Copy config
template:
src: config.j2
dest: /etc/app/config.ymlIn check mode, this compares template to destination. If destination doesn't exist:
changed: [webserver01] # Would create new fileBut the task might fail in real mode due to permissions.
Check for potential failures:
ansible-playbook site.yml --check --diffLook for warnings about permissions, missing dependencies, etc.
Step 5: Handle Conditional Tasks in Check Mode
Conditionals using ansible_check_mode behave differently:
```yaml - name: Skip in check mode command: /bin/true when: not ansible_check_mode
- name: Only in check mode
- debug:
- msg: "Running in check mode"
- when: ansible_check_mode
`
Test conditionals work:
ansible-playbook site.yml --check
ansible-playbook site.yml # Run both modes to compareStep 6: Fix Diff Output Issues
Diff shows what would change:
ansible-playbook site.yml --check --diffIf diff fails or shows nothing:
- name: Enable diff for this task
template:
src: config.j2
dest: /etc/app/config.yml
diff: yesSome modules don't support diff:
- name: No diff available
command: echo "test"
# diff not supported for commandStep 7: Handle Registered Variables in Check Mode
Variables registered in check mode may have different content:
```yaml - name: Check file stat: path: /etc/app/config.yml register: file_stat
- name: Use registered variable
- debug:
- msg: "{{ file_stat.stat.exists }}"
`
In check mode, stat runs normally (it just reads, doesn't change). But:
- name: Create file
copy:
src: config.yml
dest: /etc/app/config.yml
register: copy_resultIn check mode, copy_result shows what would change, not actual result.
Handle this:
```yaml - name: Use result safely debug: msg: "Changed in check mode: {{ copy_result.changed }}" when: ansible_check_mode
- name: Use result normally
- debug:
- msg: "Actually changed: {{ copy_result.changed }}"
- when: not ansible_check_mode
`
Step 8: Fix Tasks That Check Then Change
Tasks that check state then change can behave oddly in check mode:
```yaml - name: Check if service running command: systemctl is-active nginx register: service_status changed_when: false check_mode: no # Must run actual check
- name: Start if not running
- service:
- name: nginx
- state: started
- when: service_status.rc != 0
`
The first task must run (check_mode: no) to provide accurate input for the second.
Step 9: Handle Loops in Check Mode
Loops can behave differently in check mode:
- name: Create multiple files
file:
path: "/opt/{{ item }}"
state: directory
loop:
- app1
- app2In check mode, all loop items are evaluated:
changed: [webserver01] => (item=app1)
changed: [webserver01] => (item=app2)If one item would fail, check mode still shows others.
Step 10: Debug Check Mode Behavior
See check mode specifics:
ansible-playbook site.yml --check -vvvLook for:
check_mode: True
running checkDebug check mode value:
- name: Debug check mode
debug:
var: ansible_check_modeStep 11: Handle Module-Specific Check Mode
Many modules support check mode differently:
apt/yum modules:
- name: Install package
apt:
name: nginx
state: presentCheck mode queries package database to see if nginx installed.
file module:
- name: Create file
file:
path: /opt/app/file.txt
state: fileCheck mode checks if file exists.
template module:
- name: Deploy config
template:
src: config.j2
dest: /etc/app/config.ymlCheck mode renders template and compares to existing file.
Modules without check mode support need explicit handling:
- name: Unsupported module
my_custom_module:
param: value
check_mode: no # Force runStep 12: Verify Check Mode Accuracy
Compare check mode prediction to actual run:
```bash # First, check mode ansible-playbook site.yml --check --diff > check_output.txt
# Then, actual run ansible-playbook site.yml --diff > actual_output.txt
# Compare diff check_output.txt actual_output.txt ```
Differences indicate tasks where check mode predictions differ from reality.
Quick Verification
Test check mode works:
ansible-playbook site.yml --checkSuccess:
``` PLAY [all] ***************
TASK [Gathering Facts] *********** ok: [webserver01]
TASK [First task] *************** changed: [webserver01] # Would change in real run
PLAY RECAP *************** webserver01 : ok=2 changed=1 unreachable=0 failed=0 ```
Test with diff:
ansible-playbook site.yml --check --diffPrevention Best Practices
- 1.Test playbooks with check mode before production:
ansible-playbook production.yml --check --diff- 1.Mark check mode incompatible tasks:
- name: Run migration script
script: migrate.sh
check_mode: no- 1.Use modules that support check mode:
```yaml # Prefer - file: path=/opt/app state=directory
# Over - command: mkdir -p /opt/app ```
- 1.Handle check mode in conditionals:
when: not ansible_check_mode or check_mode_allowed- 1.Document check mode behavior:
# This role supports check mode except for:
# - migrate task (runs always)
# - restart task (skipped in check)Check mode failures typically come from incompatible modules, missing check mode markers, or tasks that must run to provide data. Use check_mode: no for critical tasks, prefer modules that support check mode, and compare predictions to actual runs.