# INJECT\_FACTS\_AS\_VARS is defaulting to False in 2.24

**URL:** <https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886>\
**Category:** Get Help\
**Tags:** ansible-core\
**Created:** [November 23, 2025, 9:09am UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886 "2025-11-23T09:09:08Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![jpmens](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/jpmens/32/5543_2.png) [@jpmens](https://forum.ansible.com/u/jpmens)\
**Post date:** [November 23, 2025, 9:09am UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/1 "2025-11-23T09:09:08Z")

</div>

I almost missed that Ansible 2.24 will be defaulting `INJECT_FACTS_AS_VARS` to `False` in future, meaning that facts like `{{ ansible_os_distribution }}` will stop working.

Instead, we’ll have to write `{{ ansible_facts['distribution'] }}`.

As somebody on the Fediverse amusingly wrote:

> Happy (careful) search & replace day through all your roles and playbooks to those who celebrate.

The original behavior can be brought back (until that is deprecated) with an `ansible.cfg` setting:

```ini
[defaults]
inject_facts_as_vars = True

```

Documented [here](https://docs.ansible.com/projects/ansible/devel/porting_guides/porting_guide_13.html#inject-facts-as-vars).

I wonder why.

---

<div class="post-metadata">

**Author:** ![felixfontein](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/felixfontein/32/7530_2.png) [@felixfontein](https://forum.ansible.com/u/felixfontein)\
**Post date:** [November 23, 2025, 10:23am UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/2 "2025-11-23T10:23:45Z")

</div>

> [@jpmens](#):
>
> As somebody on the Fediverse amusingly wrote:
> 
> > Happy (careful) search & replace day through all your roles and playbooks to those who celebrate.

The good thing is that with ansible-core 2.20+, it will tell you when you run the role/playbook/task file which places use the old way to access facts. So it’s not _that_ hard to find these places. Or at least _most_ of them…

The bad thing is that you have to pay careful attention if you’re using plugins such as community.sops.load\_vars, since you should better not change “facts” they created since they will change to real variables once ansible-core finally allows it (hopefully in 2.21). It would have been nicer if the deprecation would have only be done after allowing plugins to set variables (and not just facts)…

> [@jpmens](#):
>
> I wonder why.

Maybe the idea is to make it easier to distinguish between facts and variables. Right now their relationship is quite confusing. (And ansible.builtlin.set\_fact’s name implying that it “sets facts” while it usually sets variables is not helping…)

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [November 23, 2025, 6:17pm UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/3 "2025-11-23T18:17:59Z")

</div>

Is there an `ansible.builtin.set_var` in our future? If I’m going to have to examine all my existing `set_facts` and make syntax changes, would much rather change to a module that actually does what I want rather than uglyfy the syntax to reference “facts” that aren’t actually facts.

In all my years of Ansible use (and accumulated code), I don’t believe I have a single instance of using `set_fact` to set a fact rather than a variable.

If I understand the discussion above, I’d strongly encourage the _core_ team to reconsider the timing / ordering of these changes. We need a `set_var` before the current behavior of `set_fact` wrt variables is taken away.

---

<div class="post-metadata">

**Author:** ![felixfontein](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/felixfontein/32/7530_2.png) [@felixfontein](https://forum.ansible.com/u/felixfontein)\
**Post date:** [November 23, 2025, 6:32pm UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/4 "2025-11-23T18:32:23Z")

</div>

`ansible.builtin.set_fact` is already setting variables, you need to provide `cacheable: true` to make it also set facts. It does make sense to split up these two things though IMO.

---

<div class="post-metadata">

**Author:** ![bcoca](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/bcoca/32/9269_2.png) [@bcoca](https://forum.ansible.com/u/bcoca)\
**Post date:** [November 24, 2025, 3:14pm UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/5 "2025-11-24T15:14:06Z")

</div>

This only deprecates the default value of ‘injection’, so we can turn it off by default.

There is a plan on eventually deprecating the injection itself, but that will come later, after the revamp of `register` to add projections (probably in next version) and adding a way for actions to cleanly and purposefully set variables.

Long story about `set_fact`:  
`set_fact` was initially named `set_var` but this was misleading and `set_host_scoped_var` was … too long. So after many discussions `set_fact` was the name of compromise, misleading one as it did not ‘set a fact’, but a higher priority hope scoped variable with higher priority than facts. Eventually `cacheable` was added to allow for it also to be stored in the cache … but what really happens under the hood is that 2 variables get created, the aforementioned host scoped variable with higher precedence AND an actual fact, both set to the same value. The fact, gets cached and has ‘fact level precedence’ once retrieved from the cache, in subsequent runs, as in the ‘current’ run the host scoped variable will still exist and have the higher precedence.

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [November 24, 2025, 9:50pm UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/6 "2025-11-24T21:50:15Z")

</div>

> [@bcoca](#):
>
> but a higher priority hope scoped variable

I know it was a typo, but I _really_ like the idea of a “hope scoped variable”. Having seen it, I wonder how the field ever advanced this far without the concept.

---

<div class="post-metadata">

**Author:** ![bvitnik](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/bvitnik/32/4132_2.png) [@bvitnik](https://forum.ansible.com/u/bvitnik)\
**Post date:** [November 25, 2025, 12:37am UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/7 "2025-11-25T00:37:52Z")

</div>

> [@utoddl](#):
>
> “hope scoped variable”

I felt so stupid, uneducated and uninformed there for a minute… until… 😂

---

<div class="post-metadata">

**Author:** ![jpmens](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/jpmens/32/5543_2.png) [@jpmens](https://forum.ansible.com/u/jpmens)\
**Post date:** [November 27, 2025, 10:00am UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/8 "2025-11-27T10:00:10Z")

</div>

> [@jpmens](#):
>
> The original behavior can be brought back (until that is deprecated) with an `ansible.cfg` setting:

So I guessed right. 😑

---

<div class="post-metadata">

**Author:** ![marcelmamula](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/marcelmamula/32/9471_2.png) [@marcelmamula](https://forum.ansible.com/u/marcelmamula)\
**Post date:** [December 2, 2025, 4:08pm UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/9 "2025-12-02T16:08:05Z")

</div>

@felixfontein There is also secondary problem with this change, because it is executing on all variables in play.

This means that if someone defines their extra var with deprecated name, it will trigger only when this variable is consumed in roles, creating confusion that the role is causing it, not actual user defined variable.

Ansible-lint is also not catching this warning, which is not helping because if we could identify it in vars/facts for our roles, we could at least prevent it from our side, leaving issue only coming from user defined extra vars.

---

<div class="post-metadata">

**Author:** ![felixfontein](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/felixfontein/32/7530_2.png) [@felixfontein](https://forum.ansible.com/u/felixfontein)\
**Post date:** [December 2, 2025, 8:09pm UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/10 "2025-12-02T20:09:38Z")

</div>

> [@marcelmamula](#):
>
> This means that if someone defines their extra var with deprecated name, it will trigger only when this variable is consumed in roles, creating confusion that the role is causing it, not actual user defined variable.

I’m not sure what you mean. This doesn’t seem related to the issue in this thread, since extra vars do not define facts.

---

<div class="post-metadata">

**Author:** ![marcelmamula](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/marcelmamula/32/9471_2.png) [@marcelmamula](https://forum.ansible.com/u/marcelmamula)\
**Post date:** [December 3, 2025, 8:14am UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/11 "2025-12-03T08:14:42Z")

</div>

@felixfontein This is only topic about `INJECT_FACTS_AS_VARS` and `2.20` so I added it here.

Issue I described is specific to 2.20+ and deprecation warning, that is not accurate and it is causing confusion because of variable expansion during runtime.

Issue:

- Playbook with 10 different roles, each using input variable `__my_domain`
- Playbook executed with `__my_domain: "{{ ansible_domain }}"`
- Result: 100+ warnings for each task that uses `__my_domain`

This causes lot of confusion because it appears that roles are problem, not input variable. `ansible-lint` is also not showing this warning either.

---

<div class="post-metadata">

**Author:** ![bcoca](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/bcoca/32/9269_2.png) [@bcoca](https://forum.ansible.com/u/bcoca)\
**Post date:** [December 3, 2025, 3:01pm UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/12 "2025-12-03T15:01:31Z")

</div>

Since templating is ‘lazy’ this gets triggered every time you use (template) `ansible_domain`, there is no way to distinguish a direct vs indirect use.

---

<div class="post-metadata">

**Author:** ![flowerysong](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/flowerysong/32/2305_2.png) [@flowerysong](https://forum.ansible.com/u/flowerysong)\
**Post date:** [December 3, 2025, 5:19pm UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/13 "2025-12-03T17:19:40Z")

</div>

> [@marcelmamula](#):
>
> This causes lot of confusion because it appears that roles are problem, not input variable.

I think this is severely overstating how much potential there is for confusion.

Here’s setting a variable referenced in a role from the command line:

```console
$ ansible-playbook test.yml -e 'foo={{ ansible_fqdn }}'
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [localhost] *************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************
ok: [localhost]

TASK [foo : debug] ***********************************************************************************************************
[WARNING]: Deprecation warnings can be disabled by setting `deprecation_warnings=False` in ansible.cfg.
[DEPRECATION WARNING]: INJECT_FACTS_AS_VARS default to `True` is deprecated, top-level facts will not be auto injected after the change. This feature will be removed from ansible-core version 2.24.
Origin: <CLI option '-e'>

{{ ansible_fqdn }}

Use `ansible_facts["fact_name"]` (no `ansible_` prefix) instead.

ok: [localhost] =>
    msg: ip-10

```

Vs. setting the variable in the playbook:

```console
[DEPRECATION WARNING]: INJECT_FACTS_AS_VARS default to `True` is deprecated, top-level facts will not be auto injected after the change. This feature will be removed from ansible-core version 2.24.
Origin: /home/testing/test.yml:4:10

2 gather_facts: true
3 vars:
4 foo: "{{ ansible_fqdn }}"
           ^ column 10

Use `ansible_facts["fact_name"]` (no `ansible_` prefix) instead.

```

Vs. getting it from a host variable:

```console
[DEPRECATION WARNING]: INJECT_FACTS_AS_VARS default to `True` is deprecated, top-level facts will not be auto injected after the change. This feature will be removed from ansible-core version 2.24.
Origin: /home/testing/group_vars/all.yml:1:6

1 foo: "{{ ansible_fqdn }}"
       ^ column 6

Use `ansible_facts["fact_name"]` (no `ansible_` prefix) instead.

```

In each case I tested the warning told me exactly where the issue originated rather than pointing at the role that merely used it, even though I did my best to trick it by referencing the variable indirectly in the role:

```yaml
- debug:
    msg: "{{ bar }}"
  vars:
    bar: "{{ foo[:5] }}"

```

---

<div class="post-metadata">

**Author:** ![kpfleming](https://avatars.discourse-cdn.com/v4/letter/k/cc9497/32.png) [@kpfleming](https://forum.ansible.com/u/kpfleming)\
**Post date:** [January 10, 2026, 12:58pm UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/14 "2026-01-10T12:58:27Z")

</div>

> [@felixfontein](#):
>
> The good thing is that with ansible-core 2.20+, it will tell you when you run the role/playbook/task file which places use the old way to access facts. So it’s not _that_ hard to find these places. Or at least _most_ of them…

Unfortunately it does not tell you _which_ fact was being accessed as a variable, it only gives you a pointer to the line which caused the access to occur. In my case I have some where the line in question does not reference any facts-as-variables directly, but probably does so via a chain of template expressions, and figuring out where the variable reference exists is not trivial.

It would be very helpful if the deprecation warning message indicated which specific fact was being accessed as a variable.

---

<div class="post-metadata">

**Author:** ![felixfontein](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/felixfontein/32/7530_2.png) [@felixfontein](https://forum.ansible.com/u/felixfontein)\
**Post date:** [January 10, 2026, 1:32pm UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/15 "2026-01-10T13:32:39Z")

</div>

From my experience the error message always points to the deepest layer, so there shouldn’t be a chain of template expressions - at least from my experience so far. Do you have a specific example where this is the case?

---

<div class="post-metadata">

**Author:** ![pureeaglepiscesmilk](https://avatars.discourse-cdn.com/v4/letter/p/a9adbd/32.png) [@pureeaglepiscesmilk](https://forum.ansible.com/u/pureeaglepiscesmilk)\
**Post date:** [January 10, 2026, 3:09pm UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/16 "2026-01-10T15:09:35Z")

</div>

I think the reason for this change is to improve the flexibility and control that users have over their Ansible playbooks. By defaulting INJECT\_FACTS\_AS\_VARS to False, Ansible is shifting the responsibility of accessing facts to the user, rather than relying on the automatic injection of variables.

My suggestion is to update your playbooks to use the new syntax, as it is more explicit and consistent with Ansible’s philosophy of variable handling. If you need to preserve the original behavior, you can indeed use the ansible.cfg setting to override the default value.

Good luck with the updates!

---

<div class="post-metadata">

**Author:** ![kpfleming](https://avatars.discourse-cdn.com/v4/letter/k/cc9497/32.png) [@kpfleming](https://forum.ansible.com/u/kpfleming)\
**Post date:** [January 10, 2026, 4:54pm UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/17 "2026-01-10T16:54:08Z")

</div>

> [@felixfontein](#):
>
> Do you have a specific example where this is the case

I do, but it’s not publicly available so I’ll have to track it down and then try to make a minimal reproduction example.

> [@pureeaglepiscesmilk](#):
>
> My suggestion is to update your playbooks to use the new syntax, as it is more explicit and consistent with Ansible’s philosophy of variable handling. If you need to preserve the original behavior, you can indeed use the ansible.cfg setting to override the default value

I’m not sure what prompted this suggestion - I’m fine with updating my playbooks and roles, I’ve been doing it as I get time, but I need the hints from Ansible to know what needs to be changed as I can’t just scan every single `ansible_<foo>` reference in my entire stack (~2,500 files) to change them all.

---

<div class="post-metadata">

**Author:** ![kpfleming](https://avatars.discourse-cdn.com/v4/letter/k/cc9497/32.png) [@kpfleming](https://forum.ansible.com/u/kpfleming)\
**Post date:** [January 11, 2026, 1:06am UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/18 "2026-01-11T01:06:35Z")

</div>

OK, I figured it out… and I suppose it means the deprecation message could use a bit of improvement.

In my case I have a role which sets a cached fact named `source_python_interpreter`, and a few playbooks were evaluating that fact as a plain variable. Changing those references to `ansible_facts['source_python_interpreter']` eliminates the deprecation warning, but the warning message includes a reference to the `ansible_` prefix when the fact being evaluated may not have had an `ansible_` prefix 🙂

---

<div class="post-metadata">

**Author:** ![felixfontein](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/felixfontein/32/7530_2.png) [@felixfontein](https://forum.ansible.com/u/felixfontein)\
**Post date:** [January 11, 2026, 1:56pm UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/19 "2026-01-11T13:56:03Z")

</div>

I was able to replicate this by commenting out `self._variable_manager.set_nonpersistent_facts(target_host, result_item['ansible_facts'].copy())` in `plugins/strategy/ __init__.py` (so I don’t have to go through an actual cache 🙂 ).

I created a PR to improve the message by including the fact’s name: [Improve deprecation message for top-level facts by including the fact's name by felixfontein · Pull Request #86411 · ansible/ansible · GitHub](https://github.com/ansible/ansible/pull/86411) A side-effect is probably that if a task uses several facts, you’ll get one deprecation message per fact. I guess it’s still better than the current behavior though where you have to guess the fact’s name (especially if it doesn’t have an `ansible_` prefix).

---

<div class="post-metadata">

**Author:** ![pureeaglepiscesmilk](https://avatars.discourse-cdn.com/v4/letter/p/a9adbd/32.png) [@pureeaglepiscesmilk](https://forum.ansible.com/u/pureeaglepiscesmilk)\
**Post date:** [January 11, 2026, 6:26pm UTC](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886/20 "2026-01-11T18:26:21Z")

</div>

You’re right — I misunderstood the core issue at first.  
The challenge isn’t migrating to the new syntax, but identifying _exactly which fact_ is being accessed indirectly when Ansible raises the warning.  
I agree that having the specific fact name in the deprecation message would make large codebases much easier to update.

[Next page](https://forum.ansible.com/t/inject-facts-as-vars-is-defaulting-to-false-in-2-24/44886.md?page=2)
