# Variables from not-activated roles get set

**URL:** <https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732>\
**Category:** Get Help\
**Tags:** variables\
**Created:** [April 24, 2026, 12:38am UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732 "2026-04-24T00:38:49Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![mirabilos](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mirabilos/32/9721_2.png) [@mirabilos](https://forum.ansible.com/u/mirabilos)\
**Post date:** [April 24, 2026, 12:38am UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/1 "2026-04-24T00:38:49Z")

</div>

I want to have an Ansible-Jinja2 expression with which I can detect whether a specific variable with a dynamic name is set in host/group vars or a role that is included. (Concretely, something like `repo_backports_$distroname: true` to enable the backports repo centrally. Anything that needs backports, playbook task or role, just sets it; even one suffices for presence; none setting it will cause removal.)

I’m unable to find a way to query such a variable _dynamically_ and while debugging found that even statically does not work:

Assume two hosts, frw001 and frw254. They belong to the same group. frw001 has migrated\_to\_kea\_dhcpd set to true in hostvars, frw254 not.

I have:

```auto
$ git grep testvar
roles/common-pcengine/defaults/main.yml:testvar: false
roles/dhcpd4/defaults/main.yml:testvar: true

```

I’ve experimented already with a playbook that only includes the frw254 host:

```auto
- hosts:
  - frw254
  roles:
    - role: common-pcengine
    - role: dhcpd   
      when: not (migrated_to_kea_dhcpd | default(false))
    - role: dhcpd4
      when: (migrated_to_kea_dhcpd | default(false))

  tasks:
  - name: statically
    debug:
      msg: v={{ testvar | default(false) }},m={{ migrated_to_kea_dhcpd | default(false) }}
    tags: x

```

(Yes, this is not an MWE.)

Yet, when I start it, `testvar` shows up as true:

```auto
$ ansible-playbook playbooks/groups/pcengine.yml -l 
frw254 -t x
[…]
TASK [statically] ***********************************************************************************************
ok: [frw254] => {
    "msg": "v=True,m=False"
}

```

I’ve put `debug:` into every role file and can confirm that frw254 is in role dhcpd, not dhcpd4, so `roles/dhcpd4/defaults/main.yml` should not be read/used.

But, for some reason, it is?!

Is there a way I can trace when and from where a variable is set?

---

<div class="post-metadata">

**Author:** ![mirabilos](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mirabilos/32/9721_2.png) [@mirabilos](https://forum.ansible.com/u/mirabilos)\
**Post date:** [April 24, 2026, 12:41am UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/2 "2026-04-24T00:41:34Z")

</div>

> [@mirabilos](#):
>
> ```
> roles/dhcpd4/defaults/main.yml:testvar: true
> 
> ```

btw, if I comment that one out, it does show false, so nothing _else_ sets this variable

---

<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:** [April 24, 2026, 1:39am UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/3 "2026-04-24T01:39:53Z")

</div>

imported roles ALWAYS set the variables, the question is ‘when’ does it happen, defaults are special in many ways, also being the lowest precedence. A role will take it’s own defaults over other role defaults when in conflict, but the variable will be set if at all defined in the role and will affect subsequent roles and tasks depending on the import order.

---

<div class="post-metadata">

**Author:** ![mirabilos](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mirabilos/32/9721_2.png) [@mirabilos](https://forum.ansible.com/u/mirabilos)\
**Post date:** [April 24, 2026, 1:47am UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/4 "2026-04-24T01:47:59Z")

</div>

But the role `dhcpd4` _isn’t_ imported, because the `migrated_to_kea_dhcpd` variable is not set and thus defaults to false.

> [@bcoca](#):
>
> but the variable will be set if at all defined in the role and will affect subsequent roles and tasks depending on the import order.

That’s actually what I want… but only if the role is actually used!

---

<div class="post-metadata">

**Author:** ![mirabilos](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mirabilos/32/9721_2.png) [@mirabilos](https://forum.ansible.com/u/mirabilos)\
**Post date:** [April 24, 2026, 2:14am UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/5 "2026-04-24T02:14:22Z")

</div>

Here’s an MWE exhibiting the bug:

```auto
tg@tgb1:/tmp/mwe $ cat roles/extra/defaults/main.yml
foo: true
tg@tgb1:/tmp/mwe $ cat roles/extra/tasks/main.yml
---
- name: hi from role extra
  debug: msg=hi
tg@tgb1:/tmp/mwe $ cat testplay.yml
- hosts: localhost
  become: false
  gather_facts: false
  roles:
  - role: extra
    when: false
  tasks:
  - name: variable test
    debug:
      msg: variable foo={{ foo | default(false) }}
tg@tgb1:/tmp/mwe $ ansible-playbook testplay.yml                                                                
[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 [extra : hi from role extra] *******************************************************************************
skipping: [localhost]
 
TASK [variable test] ********************************************************************************************
ok: [localhost] => {
    "msg": "variable foo=True"
}
 
PLAY RECAP ******************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0   
 

```

If I comment out the line in `roles/extra/defaults/main.yml` it correctly shows False.

---

<div class="post-metadata">

**Author:** ![mirabilos](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mirabilos/32/9721_2.png) [@mirabilos](https://forum.ansible.com/u/mirabilos)\
**Post date:** [April 24, 2026, 2:17am UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/6 "2026-04-24T02:17:37Z")

</div>

using `- role: "{{ 'extra' if false else omit }}"` also does not work

---

<div class="post-metadata">

**Author:** ![mirabilos](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mirabilos/32/9721_2.png) [@mirabilos](https://forum.ansible.com/u/mirabilos)\
**Post date:** [April 24, 2026, 2:20am UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/7 "2026-04-24T02:20:46Z")

</div>

in the more concrete case…

```
- role: "{{ (migrated_to_kea_dhcpd | default(false)) | ternary('dhcpd4', 'dhcpd') }}"

```

… also does not work right: the variable is ignored and even the migrated host suddenly uses the old role `dhcpd` instead, so this is also broken.

---

<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:** [April 24, 2026, 3:21am UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/8 "2026-04-24T03:21:03Z")

</div>

imports are NOT conditional, `roles` works like `import_role`. The `when` is applied to task execution, it does not affect importing of variables, you need to use `include_role` if you want that functionality.

---

<div class="post-metadata">

**Author:** ![mirabilos](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mirabilos/32/9721_2.png) [@mirabilos](https://forum.ansible.com/u/mirabilos)\
**Post date:** [April 24, 2026, 3:23am UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/9 "2026-04-24T03:23:05Z")

</div>

… ah!

That is… annoying, as `import_role` is imperative and doesn’t work with role dependencies.

---

<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:** [April 24, 2026, 3:23am UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/10 "2026-04-24T03:23:55Z")

</div>

roles, import\_role and include\_role are all ‘imperative’ and all work with dependencies.

---

<div class="post-metadata">

**Author:** ![kks](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/kks/32/10352_2.png) [@kks](https://forum.ansible.com/u/kks)\
**Post date:** [April 24, 2026, 7:05am UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/11 "2026-04-24T07:05:01Z")

</div>

> [@mirabilos](#):
>
> with which I can detect whether a specific variable with a dynamic name is set in host/group vars or a role that is included

As far I understand it is impossible to read variable value at specific precedence level (in this case host/group/role). If variables are read they are always read from higher precedence to lowest. So if on any precendence level value is set (in the scope where read is happening), variable is considered set.

> [@mirabilos](#):
>
> `testvar` shows up as true:

This is because as was mentioned playbook directive `role:` is same as `import_role` and `import_role` default behavior when making role variables public, is opposite to `include_role` (which does not make any variables public by default)

> **[Parameters - ansible.builtin.import\_role module – Import a role into a play —...](https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/import_role_module.html#parameter-public)**
>
> Parameter

parameter `public` is set to `true` by default. So all role variables are public after role import.

Try setting it to `false` and use `import_role` explicitly, instead or `role`, role variables (defaults, vars) will not be public, so they will not affect anything “outside” the role.

---

<div class="post-metadata">

**Author:** ![kks](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/kks/32/10352_2.png) [@kks](https://forum.ansible.com/u/kks)\
**Post date:** [April 24, 2026, 7:14am UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/12 "2026-04-24T07:14:19Z")

</div>

> [@bcoca](#):
>
> imported roles ALWAYS set the variables

But variables are not always _public_, they are not always “visible” to subsequent actions.  
As mentioned in the docs for `public` parameter

> **[Parameters - ansible.builtin.import\_role module – Import a role into a play —...](https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/import_role_module.html#parameter-public)**
>
> Parameter

---

<div class="post-metadata">

**Author:** ![kks](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/kks/32/10352_2.png) [@kks](https://forum.ansible.com/u/kks)\
**Post date:** [April 24, 2026, 7:22am UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/13 "2026-04-24T07:22:56Z")

</div>

> [@bcoca](#):
>
> imports are NOT conditional

Just to expand and clarify on this statement.  
Role imports with `import_role` are not conditional in a sense that if directive `when` is evaluated to `false`, role is anyway imported. But no actions from the role will be executed, as they will all “inherit” `when: false` that is why they will not be executed. But other steps of role import, for instance vars and defaults imports, will be executed.

Role imports are conditional in a sense that one can import different roles using logical conditions in jinja expressions in the role name.

---

<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:** [April 24, 2026, 2:14pm UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/14 "2026-04-24T14:14:45Z")

</div>

yes, you can change which role is imported dynamically (limited to variables available at import time), but you cannot make conditional the action of importing, only of including.

with imports the variables are always imported, but not always published to the play scope, that is what `public` controls, any roles or tasks included/imported inside said role will still get access to those variables as they are still in the same context.

---

<div class="post-metadata">

**Author:** ![mirabilos](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mirabilos/32/9721_2.png) [@mirabilos](https://forum.ansible.com/u/mirabilos)\
**Post date:** [April 24, 2026, 3:28pm UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/15 "2026-04-24T15:28:53Z")

</div>

But I need them public… iff the role gets imported/executed. And then, visible to the `common` role that runs before, so `set_fact` is out.

I fear I’ll have to do this entirely differently, which sucks because then, cleanup once no longer needed is going to be annoying.

---

<div class="post-metadata">

**Author:** ![kks](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/kks/32/10352_2.png) [@kks](https://forum.ansible.com/u/kks)\
**Post date:** [April 24, 2026, 3:49pm UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/16 "2026-04-24T15:49:47Z")

</div>

> [@mirabilos](#):
>
> But I need them public…

> [@mirabilos](#):
>
> I want to have an Ansible-Jinja2 expression with which I can detect whether a specific variable with a dynamic name is set in host/group vars or a role that is included.

What do you what to achieve by this? Not from ansible point of view (what variables to set), but from what do you want to do on your hosts?

---

<div class="post-metadata">

**Author:** ![mirabilos](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mirabilos/32/9721_2.png) [@mirabilos](https://forum.ansible.com/u/mirabilos)\
**Post date:** [April 24, 2026, 3:51pm UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/17 "2026-04-24T15:51:46Z")

</div>

I have a `common` role that creates the APT sources.

I have some roles that need extra repos included, such as backports now concretely.

I toucht the roles could set a variable when included, and the common role could then know the variable and, if present, include the extra repo in the APT sources, and otherwise not, making removal automatic.

---

<div class="post-metadata">

**Author:** ![kks](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/kks/32/10352_2.png) [@kks](https://forum.ansible.com/u/kks)\
**Post date:** [April 24, 2026, 4:05pm UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/18 "2026-04-24T16:05:02Z")

</div>

I see this like this in my head.

Role 1

```yaml
- name: Are extra repos needed?
...
Here is a task or tasks to understand if extra repos are needed
...

- name: Set variable role1_extra_repos_needed
  set_fact:
     role1_extra_repos_needed: true / false

```

Playbook

```yaml
- name: Playbook
  hosts: all
  gather_facts: false
  tasks:
    - include_role: role1 
    - include_role: common
      vars:
        common_extra_repos_needed: "{{ role1_extra_repos_needed }}"

```

You can even remove role1 from the playbook by making it a dependency of role common.

role common meta/main.yml file

```yaml
dependencies:
  - role: role1
 

```

Playbook

```yaml
- name: Playbook
  hosts: all
  gather_facts: false
  tasks:
    - include_role: common
      vars:
        common_extra_repos_needed: "{{ role1_extra_repos_needed }}"

```

After that you can remove line to set common\_extra\_repos\_needed if you set its default value in common role

role common default/main.yml file

```yaml
common_extra_repos_needed: "{{ role1_extra_repos_needed | default(omit) }}"

```

Here if variable role1\_extra\_repos\_needed is not defined variable common\_extra\_repos\_needed also will not be defined, and not just set to empty string. That is why `default(omit)` is required.

Playbook

```yaml
- name: Playbook
  hosts: all
  gather_facts: false
  tasks:
    - include_role: common

```

---

<div class="post-metadata">

**Author:** ![mirabilos](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mirabilos/32/9721_2.png) [@mirabilos](https://forum.ansible.com/u/mirabilos)\
**Post date:** [April 24, 2026, 6:32pm UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/19 "2026-04-24T18:32:29Z")

</div>

Yes, except the `common` role runs first, for all hosts (not just those that include the repo)…

I’ll have to solve this differently.

---

<div class="post-metadata">

**Author:** ![mirabilos](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/mirabilos/32/9721_2.png) [@mirabilos](https://forum.ansible.com/u/mirabilos)\
**Post date:** [April 24, 2026, 6:43pm UTC](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732/20 "2026-04-24T18:43:04Z")

</div>

Basically: the `common` role must add more to the `sources.list.d/all.sources` file if the host _later_ runs the `dhcpd4` role.

> I’ll have to solve this differently.

Or I’ll just have to live with the bug. For the current specific case, I only need trixie-backports, packages from which are not installed by default anyway, so if it gets enabled on more systems than strictly needed, it may be not a problem.

Still, Ansible is **so** close to getting things right, and then that. The `when:` in a role dependency needs to skip the `defaults/main.yml`, not just the tasks.

[Next page](https://forum.ansible.com/t/variables-from-not-activated-roles-get-set/45732.md?page=2)
