# Cannot change a variable passed to a role from within a role - request for docs

**URL:** <https://forum.ansible.com/t/cannot-change-a-variable-passed-to-a-role-from-within-a-role-request-for-docs/45368>\
**Category:** Get Help\
**Tags:** variables, role\
**Created:** [February 19, 2026, 7:10pm UTC](https://forum.ansible.com/t/cannot-change-a-variable-passed-to-a-role-from-within-a-role-request-for-docs/45368 "2026-02-19T19:10:17Z")\
**Posts on this page:** 1\
**Showing post:** 11

<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:** [February 20, 2026, 4:25pm UTC](https://forum.ansible.com/t/cannot-change-a-variable-passed-to-a-role-from-within-a-role-request-for-docs/45368/11 "2026-02-20T16:25:01Z")

</div>

I’m quoting your initial “Simulated Playbook (code not tested)” here because I want to point out something that I think is relevant to your situation. The preceding discussions of variable precedence and playbook vs. host scopes are all well and good, but you need a strategy to deal with this information.

> [@maxwax99](#):
>
> ```yaml
> - name: Set config value
> ansible.builtin.set_fact:
> my_role_config:
> - apple
> - banana
> - apple
> - blueberry
> - apple
> 
> - name: Include modular role
> ansible.builtin.include_role:
> name: my_role
> tasks_from: main.yml
> vars:
> my_role_config: "{{ my_role_config }}"
> 
> ```

That wouldn’t pass code review in our shop. You’ve got two, maybe three separate things here depending on how your count them, all with the same name – a recipe for confusion.

Now that you’ve become aware of how scoping and precedence interact (to over-generalize, hoping that things will “just work” is insufficient), you need some guidelines for when data goes through various “scope transitions”. For our purposes a _scope transition_ includes data from _outside_ of a role being passed to or used _inside_ of roles.

Taking the example above, the `set_fact` above is fine in and of itself, but it’s happening outside of the `my_role` role, so it’s name should reflect that out-of-role origin — well, at least to the extent that it shouldn’t have a name that makes it look like a role variable. Call it something else, then be explicit about the _scope transition_ when you do the `include_role`:

```yaml
- name: Set the list of relevant fruits
  ansible.builtin.set_fact:
    fruits_of_my_loom:
      - apple
      - banana
      - apple
      - blueberry
      - apple

- name: Include modular role
  ansible.builtin.include_role:
    name: my_role
    tasks_from: main.yml
  vars:
    my_role_config: "{{ fruits_of_my_loom }}"

```

After which `my_role_config` only exists in the context of this host’s invocation of `my_role`.

Likewise, any `set_fact`s done within a role should (and these are _our_ _guidelines_, not _rules_, so “should” rather than “must”) be prefixed with the role name. Therefore any data prefixed by `my_role_` was either passed to the role explicitly, `set_fact`ed by the role (that’s how the role exposes values it wants to “export”), or came from role defaults or role vars.

Here’s a case where the above was causing minor confusion and how we fixed it. We set a variable in `group_vars/mw_itweb_non.yml` (non-prod apache httpd servers) that was

```yaml
mw_common_apache_module_override :
  - 'ssl'
  - ['mpm_prefork', false]
  - ['mpm_worker', true]
  - 'proxy_wstunnel'

```

This is used by our `mw_common_apache` role to override that role’s default list of which apache modules to load. The confusion arose because it wasn’t set where the role was invoked, nor in the role itself. We renamed the variable `mw_itweb_apache_module_override` to match the related adjacent variables (still not great, but at least consistent), and assigned the role variable at role invocation:

```yaml
- name: Common apache configuration
  ansible.builtin.include_role:
    name: mw_common_apache
  vars:
    mw_common_apache_version: "{{ mw_itweb_common_config.apache }}"
    mw_common_apache_server_doc_root: "{{ mw_itweb_common_config.docroot }}"
    mw_common_apache_instance: "{{ mw_itweb_apache_instance }}"
    mw_common_apache_service_type: "{{ mw_itweb_common_config.type | d('init') }}"
    mw_common_apache_port: "{{ mw_itweb_common_config.port }}"
    mw_common_apache_timeout: '120'
    mw_common_apache_shibboleth: true
    mw_common_apache_config_notify: "apache_config_change_{{ mw_itweb_common_config.type }}"
    mw_common_apache_module_override: "{{ mw_itweb_apache_module_override }}"
    mw_common_apache_mpm_worker_maxrequestworkers: "{{ mw_itweb_mpm_worker_maxrequestworkers | d(1000) }}"

```

We bend these guidelines when relevant data comes from multiple places – group\_vars, host\_vars, role defaults – and get combined by name. For example, our `splunk_forwarder` role contains the default variable `splunk_forwarder_inputs_conf_defaults`, but various group\_vars or host\_vars may exist for the current play host that should be combined with. They would have names like `splunk_forwarder_inputs_conf_fwhostd0p` or `splunk_forwarder_inputs_conf_fwgrp4`. A `template` task within the `splunk_forwarder` role combines these variables in its `vars:` section as shown below:

```yaml
- name: Populate splunk inputs.conf
  become: true
  become_user: splunk
  ansible.builtin.template:
    src: '{{ splunk_forwarder_inputsconf }}'
    dest: '{{ splunk_forwarder_homedir }}/etc/system/local/inputs.conf'
    owner: splunk
    group: splunk
    mode: 0644
  notify: restart splunkforwarder
  vars:
    # 'conf_var_names' contains a list of all the variables starting with
    # "splunk_forwarder_inputs_conf_" except "…defaults".
    conf_var_names: "{{ [ [lookup('ansible.builtin.varnames',
                                 '^splunk_forwarder_inputs_conf_(?!defaults$).*', default='')]
                        ] | flatten
                        | map('split', ',')
                        | flatten }}"
    # Combine the 'splunk_forwarder_inputs_conf_defaults' role default
    # and any host- or group-specific inputs_conf variables that might
    # apply to the current play host.
    conf_var_values: "{{ splunk_forwarder_inputs_conf_defaults
                        | combine(lookup('ansible.builtin.vars', *conf_var_names)) }}"

```

(There’s also the `community.general.merge_variables` lookup that could be used if your variable names let you get the defaults combined first. We did it this way because - say it with me - “We’ve always done it this way.”)

---

_[View the full topic](https://forum.ansible.com/t/cannot-change-a-variable-passed-to-a-role-from-within-a-role-request-for-docs/45368)._
