The non-existence of local facts means Ansible cannot check the existence of a local fact

I have a playbook that checks the existence of a local fact, but not every hosts have this local fact.

On servers where it does not exist my playbook fails with:

“msg”: "The conditional check ‘ansible_local[‘my_fact’][‘default’][‘name’] is defined’ failed. The error was: error while evaluating conditional (ansible_local[‘my_fact’][‘default’][‘name’] is defined): ‘dict object’ has no attribute ‘my_fact’

This is quite annoying. I think I can work around it by checking the existence of the local fact file, but it feels like I’m missing something obvious.

You need to use the default filter
https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#defaulting-undefined-variables

And you need to use the filter on every sub attribute.
So something like this should work

((ansible_local['my_fact'] | default({}))['default'] | default({}))['name'] | default({})

or a more flexible conditional:

when: "'my_fact' in ansible_local and
ansible_local['my_fact']['default']['name'] is defined"

FYI, in newer version of Ansilbe, `ansible_local` is always defined,
even if empty, so no need to use default on it

Sadly, neither the suggested solutions worked. I’m using Ansible 2.5.2 BTW.

The workaround I came up with was:

  • name: Check if local fact exists
    stat:
    path: /etc/ansible/facts.d/my_fact.fact
    register: local_fact

  • name: Create empty local fact
    ini_file:
    path: /etc/ansible/facts.d/my_fact.fact
    section: “default”
    option: “{{ item.option }}”
    value: “{{ item.value }}”
    with_items:

  • { option: “name”, value: “” }

  • { option: “key”, value: “” }
    when: local_fact.stat.exists == False

  • name: read local facts
    setup:
    filter=ansible_local

or a more flexible conditional:

when: "'my_fact' in ansible_local and
ansible_local['my_fact']['default']['name'] is defined"

To OP you might need to add is defined on ansible_local['my_fact']['default'] too, depending on you variables.

FYI, in newer version of Ansilbe, `ansible_local` is always defined,
even if empty, so no need to use default on it

FYI, I did not use default on ansible_local, only my_fact, default and name.