When working with Ansible's json_query
filter, you might encounter this frustrating scenario where the system insists you need jmespath installed - even when package managers confirm it's already present.
# Typical error message:
fatal: [host]: FAILED! => {"msg": "You need to install \"jmespath\" prior to running json_query filter"}
First, let's confirm what we're seeing:
# Check system package
$ sudo dnf list installed python3-jmespath
python3-jmespath-0.9.0-11.el8.noarch
# Check pip installation
$ pip3 show jmespath
Name: jmespath
Version: 0.9.0
Location: /usr/lib/python3.6/site-packages
This usually happens due to one of these scenarios:
- Ansible is using a different Python interpreter than your system default
- The environment where Ansible runs doesn't have access to the system packages
- Permission issues preventing module loading
First, identify which Python Ansible is actually using:
$ ansible --version
ansible [core 2.12.2]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.6/site-packages/ansible
executable location = /usr/bin/ansible
python version = 3.6.8 (default, Aug 24 2020, 17:57:11) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]
Solution 1: Install for the correct Python environment
$ /usr/bin/python3.6 -m pip install jmespath
Solution 2: Force ansible to use system packages
Add this to your ansible.cfg:
[defaults]
interpreter_python = /usr/bin/python3
Solution 3: Use ansible_python_interpreter
# In your inventory file:
[all:vars]
ansible_python_interpreter=/usr/bin/python3
If you're still having issues, consider these workarounds:
# Use yq (YAML processor) as alternative
- name: Process JSON with yq
command: yq e '.list1[].name' <(echo "{{ data | to_json }}")
register: result
# Or use jq if available
- name: Process with jq
command: jq '.list1[].name' <(echo "{{ data | to_json }}")
register: result
After applying any solution, test with this simple playbook:
---
- name: Test JMESPath installation
hosts: localhost
tasks:
- name: Test json_query
debug:
msg: "{{ [{'name': 'test'}] | json_query('[0].name') }}"
When working with Ansible's powerful json_query
filter, encountering the "You need to install jmespath" error while the package is clearly installed can be particularly frustrating. Let's dive into the various aspects of this issue and explore comprehensive solutions.
First, let's verify all possible installation locations:
# Check system package
rpm -qa | grep jmespath
# Check pip installations
pip3 list | grep jmespath
pip3 show jmespath
# Check Python path
python3 -c "import sys; print(sys.path)"
The issue typically stems from one of these scenarios:
- Ansible running with a different Python interpreter than expected
- Multiple Python versions causing path confusion
- Virtual environment isolation issues
- SELinux context problems (common on RHEL-based systems)
Solution 1: Explicitly Set Python Interpreter
Add this to your ansible.cfg or inventory file:
[defaults]
interpreter_python = /usr/bin/python3
Solution 2: Force Reinstallation for All Users
sudo pip3 install --force-reinstall --ignore-installed jmespath
Solution 3: Virtual Environment Approach
Create a clean virtual environment:
python3 -m venv ansible_venv
source ansible_venv/bin/activate
pip install ansible jmespath
For persistent cases, try this diagnostic playbook:
---
- name: Debug Python environment
hosts: localhost
tasks:
- name: Show Python path
debug:
msg: "{{ ansible_python.interpreter }}"
- name: Test jmespath import
command: "{{ ansible_python.interpreter }} -c 'import jmespath; print(jmespath.__file__)'"
register: jmespath_test
- name: Show jmespath location
debug:
var: jmespath_test.stdout
If you continue having issues, consider using the native json
filter with map
:
loop: "{{ data.list1 | map(attribute='name') | list }}"
After applying fixes, test with this simple playbook:
---
- name: Test jmespath functionality
hosts: localhost
vars:
test_data:
- {name: item1, value: 10}
- {name: item2, value: 20}
tasks:
- name: Test json_query
debug:
msg: "{{ test_data | json_query('[].name') }}"