Undefined variable error in Ansible check mode when referencing ansible_facts without credentials
0 reputation · 26 Oct 2022, 15:05 UTC
0 reputation · 26 Oct 2022, 15:05 UTC
When running an Ansible playbook in check mode (--check) without supplying remote credentials, the intent is to validate syntax and logic without making any changes. However, if the playbook contains Jinja2 templates or variable expressions that reference facts such as {{ ansible_facts['distribution'] }}, check mode still attempts to evaluate those expressions. Because fact gathering cannot proceed without a valid connection, the variables remain undefined, causing the playbook to fail with an “undefined variable” error even though no task would modify the remote system.
This behavior raises uncertainty about whether check mode can be relied upon for dry‑run validation when credentials are intentionally omitted. It also prompts the question of how to supply placeholder facts or suppress fact gathering solely to allow template evaluation during a check‑run without exposing sensitive data.
Can fact gathering be disabled or bypassed for check mode while still permitting Jinja2 templates to reference fact‑based variables?
Is there a supported method to inject local dummy facts (e.g., via vars or fact cache) to satisfy template evaluation without requiring remote credentials?
32775 reputation · 26 Oct 2022, 20:02 UTC
Yes. You can prevent the undefined‑variable error by either disabling fact gathering for the check‑run or by supplying dummy facts locally. Both approaches keep check mode a true dry‑run because no remote modules are executed.
Ansible’s check mode still runs the implicit setup task (fact gathering) unless you explicitly set gather_facts: false. Without valid SSH credentials the setup module fails, leaving ansible_facts undefined, which causes Jinja2 references such as {{ ansible_facts['distribution'] }} to raise an “undefined variable” error.
gather_facts: false at the play, block, or task level stops the setup task from running.vars:, -e on the command line, or a set_fact task delegated to localhost.jsonfile) lets you pre‑populate a cache file with the needed facts; Ansible reads the cache during check mode without attempting a remote connection.gather_facts: false to your play (or to a specific block). - hosts: all
gather_facts: false
vars:
distribution: "Ubuntu"
tasks:
- debug:
msg: "Distribution is {{ distribution }}"
Run with ansible-playbook --check -v playbook.yml. - hosts: all
vars:
ansible_facts:
distribution: "CentOS"
tasks:
- debug:
msg: "Running on {{ ansible_facts.distribution }}"
Again run in check mode. - hosts: all
gather_facts: true
pre_tasks:
- delegate_to: localhost
set_fact:
ansible_facts:
distribution: "Debian"
tasks:
- debug:
msg: "Detected {{ ansible_facts.distribution }}"
Run with --check.# fact_cache.json
{
"ansible_facts": {
"distribution": "Amazon Linux"
}
}
- hosts: all
gather_facts: true
vars:
fact_caching: jsonfile
fact_caching_connection: ./fact_cache
tasks:
- debug:
msg: "Cache says {{ ansible_facts.distribution }}"
Execute ansible-playbook --check -v playbook.yml.To confirm the fix, run the playbook in check mode with verbose output; you should see the debug task succeed and no “undefined variable” messages. As a negative check, revert to gather_facts: true (default) and omit credentials; the run will fail at the setup step, proving the error originates from missing fact gathering.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.