# Passing condition to "failed\_when" as a variable

**URL:** <https://forum.ansible.com/t/passing-condition-to-failed-when-as-a-variable/45530>\
**Category:** Get Help\
**Created:** [March 15, 2026, 1:08pm UTC](https://forum.ansible.com/t/passing-condition-to-failed-when-as-a-variable/45530 "2026-03-15T13:08:34Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Openuser87](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/openuser87/32/10468_2.png) [@Openuser87](https://forum.ansible.com/u/Openuser87)\
**Post date:** [March 15, 2026, 1:08pm UTC](https://forum.ansible.com/t/passing-condition-to-failed-when-as-a-variable/45530/1 "2026-03-15T13:08:34Z")

</div>

I try to pass a condition to `failed_when` as a variable in a role:

`my-role/defaults/main.yml`:

```auto
# list of commands to execute in form [command, changed_when, failed_when]

my_commands:
  - ["myapp init", "cmd_result.rc == 0", "(cmd_result.rc != 0) and ('Non-critical error' not in cmd_result.stdout) and ('Non-critical error' not in cmd_result.stderr)"]
  - [...]

```

This would allow me to loop through the command list with custom `changed_when` and `failed_when` conditions:

`my-role/tasks/main.yml`:

```auto
- name: Execute commands
  ansible.builtin.include_tasks: my-task.yml
  loop: "{{ my_commands }}"
  loop_control:
    loop_var: my_command

```

`my-role/tasks/my-task.yml`:

```auto
- name: My task
 ansible.builtin.command: "{{ my_command[0] }}"
  register: cmd_result
  changed_when: my_command[1]
  failed_when: my_command[2]

```

But I face following behaviour:

- task fails with `non-zero return code` ❌
- if I copy the condition line into `failed_when` statement explicitly, like `failed_when: "(cmd_result.rc != 0) and ('Non-critical error' not in cmd_result.stdout) and ('Non-critical error' not in cmd_result.stderr)"`, task works ✅

I _suppose_ it may be that

- the statement is not evaluated properly
- `cmd_result` variable is not injected into the conditional statement

Can anyone explain this, and maybe suggest an elegant and functional way to get this work?

Thank you!

---

<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:** [March 15, 2026, 1:26pm UTC](https://forum.ansible.com/t/passing-condition-to-failed-when-as-a-variable/45530/2 "2026-03-15T13:26:49Z")

</div>

> [@Openuser87](#):
>
> ```auto
> my_commands:
> - ["myapp init", "cmd_result.rc == 0", "(cmd_result.rc != 0) and ('Non-critical error' not in cmd_result.stdout) and ('Non-critical error' not in cmd_result.stderr)"]
> - [...]
> 
> ```

> [@Openuser87](#):
>
> `failed_when: my_command[2]`

failed\_when is evaluated to literal string “(cmd\_result.rc != 0) and (‘Non-critical error’ not in cmd\_result.stdout) and (‘Non-critical error’ not in cmd\_result.stderr)”

What you want is to have same literal string “(cmd\_result.rc != 0) and (‘Non-critical error’ not in cmd\_result.stdout) and (‘Non-critical error’ not in cmd\_result.stderr)” to be used as condition.

In your case there is only one evaluation - my\_command[2] is evaluated to string, ansible does just one evaluation.

The solution is

```yaml

failed_when: "{{ my_command[2] }}"

```

In this case `{{ my _command[2] }}` is evaluated to as string (variable evaluation) and when string (condition you wrote) is evaluated as condition.

---

<div class="post-metadata">

**Author:** ![vbotka](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/vbotka/32/359_2.png) [@vbotka](https://forum.ansible.com/u/vbotka)\
**Post date:** [March 16, 2026, 1:46am UTC](https://forum.ansible.com/t/passing-condition-to-failed-when-as-a-variable/45530/3 "2026-03-16T01:46:47Z")

</div>

> [@Openuser87](#):
>
> This would allow me to loop through the command list

Create the files on the fly. For example,

```yaml
    - name: Create my commands.
      run_once: true
      delegate_to: localhost
      block:

        - name: Create directory for my commands.
          file:
            state: directory
            path: /tmp/my_commands

        - name: Create my commands.
          copy:
            dest: "{{ my_task }}"
            content: |
              ---
              - name: My task
                ansible.builtin.command: "{{ item.0 }}"
                register: cmd_result
                changed_when: "{{ item.1 }}"
                failed_when: "{{ item.2 }}"
          loop: "{{ my_commands }}"
          loop_control: 
            extended: true

```

Declare the filename as appropriate

```yaml
my_task: "/tmp/my_commands/{{ ansible_loop.index }}-{{ item.0 }}.yml"

```

Then, execute the commands

```yaml
    - name: Execute my commands.
      ansible.builtin.include_tasks: "{{ my_task }}"
      loop: "{{ my_commands }}"
      loop_control: 
        extended: true

```

[[source code]](https://github.com/vbotka/ansible_qa/tree/master/tasks/forum-45530)

---

<div class="post-metadata">

**Author:** ![shertel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/shertel/32/1241_2.png) [@shertel](https://forum.ansible.com/u/shertel)\
**Post date:** [March 16, 2026, 2:00pm UTC](https://forum.ansible.com/t/passing-condition-to-failed-when-as-a-variable/45530/4 "2026-03-16T14:00:23Z")

</div>

As mentioned already, the items in my\_command are all strings, not variables. If you look at `changed_when_result` in the output - you’ll see a message that it’s derived from a string. If you fix that by adding brackets around the 2nd and 3rd fields for every item in my\_commands, you’ll run into another issue: the loop is templated before the task executes. I’d use two different variables - one for the loop, and another that is referenced by `changed_when` and `failed_when` using the loop item.

For example, the variables could look like:

```yaml
my_commands:
  - myapp init
cmd_results:
  # Or, instead of a dict, you could use a list with the same indices
  # as in my_commands, and loop over "{{ range(0, my_commands|length) | list }}".
  "myapp init":
    changed_when: "{{ cmd_result.rc == 0 }}"
    failed_when:
      - "{{ cmd_result.rc != 0 }}"
      - "{{ 'Non-critical error' not in cmd_result.stdout }}"
      - "{{ 'Non-critical error' not in cmd_result.stderr }}"

```

And could be used in the task like:

```yaml
changed_when: cmd_results[my_command].changed_when
failed_when: cmd_results[my_command].failed_when is all

```
