Ansible Error Guide: 'target uses selinux but python bindings aren't installed' — Fix
Fix Ansible's 'Aborting, target uses selinux but python bindings (libselinux-python) aren't installed' error: install libselinux for the right interpreter and match SELinux state.
- #ansible
- #automation
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
This error means Ansible detected that SELinux is enabled on the target host, but the Python libselinux bindings that let a module read or set SELinux file contexts are missing for the Python interpreter Ansible is using. It typically fires from file-touching modules (copy, template, file, lineinfile) that need to preserve or set an SELinux context, and from the selinux/seboolean modules directly.
The literal message:
fatal: [db-01]: FAILED! => {"changed": false, "msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren't installed"}
A closely related variant names the module or the missing library explicitly:
fatal: [db-01]: FAILED! => {"changed": false, "msg": "Failed to import the required Python library (libselinux) on db-01's Python /usr/bin/python3.9. Please read the module documentation and install it in the appropriate location."}
The fix is almost always to install the libselinux Python bindings for the exact interpreter Ansible runs on the target — not just any Python on the box.
Symptoms
- A
copy,template,file, orlineinfiletask fails on a Red Hat / CentOS / Rocky / Alma / Fedora host with thelibselinux-pythonmessage. - The
ansible.posix.selinuxorsebooleanmodule refuses to run. - The task works on Ubuntu/Debian targets but fails on RHEL-family hosts.
- The host has SELinux in
enforcingorpermissivemode (notdisabled). libselinuxis installed for the system Python but Ansible is using a different interpreter (a venv,/usr/bin/python3.11, or a custom path).
ansible-playbook -i inventory.ini site.yml --limit db-01
fatal: [db-01]: FAILED! => {"msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren't installed"}
Common Root Causes
1. The bindings are simply not installed
A minimal RHEL-family image ships without the SELinux Python bindings.
ansible db-01 -i inventory.ini -m command -a "rpm -q libselinux python3-libselinux"
package python3-libselinux is not installed
2. Bindings installed for the wrong interpreter
Ansible is configured to use a specific interpreter (venv or newer Python) that lacks the bindings, while the system Python has them.
ansible db-01 -i inventory.ini -m setup -a "filter=ansible_python*"
"ansible_python_interpreter": "/opt/venv/bin/python3.11"
The python3-libselinux RPM installs into /usr/lib64/python3.9/..., not the venv — so the venv interpreter cannot import it.
3. Wrong package name for the Python version
On Python 2 hosts the package is libselinux-python; on Python 3 it is python3-libselinux. Installing the wrong one leaves the active interpreter without bindings.
4. SELinux enabled but you assumed it was off
The host was rebuilt or a base image changed SELinux from disabled to enforcing, so a playbook that never needed the bindings suddenly does.
ansible db-01 -i inventory.ini -m command -a "getenforce"
Enforcing
Diagnostic Workflow
Step 1: Confirm SELinux is actually active on the target
If SELinux is disabled, this error should not appear; if it does, the state changed recently.
ansible db-01 -i inventory.ini -m command -a "getenforce"
Enforcing
Step 2: Identify the exact interpreter Ansible uses
This is the crux — the bindings must exist for this interpreter, not the system default.
ansible db-01 -i inventory.ini -m setup -a "filter=ansible_python_interpreter"
db-01 | SUCCESS => {
"ansible_facts": { "ansible_python_interpreter": "/usr/bin/python3" }
}
Step 3: Check whether that interpreter can import selinux
Probe the real interpreter directly rather than trusting rpm -q:
ansible db-01 -i inventory.ini -m command -a "/usr/bin/python3 -c 'import selinux; print(selinux.is_selinux_enabled())'"
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'selinux'
A traceback here proves the binding is missing for that interpreter.
Step 4: Install the correct bindings with the right package name
Use the package that matches the interpreter’s Python major version. Note the chicken-and-egg: install with dnf/yum (which pre-date the SELinux binding requirement), not with a copy-based task:
- name: Ensure SELinux Python bindings are present
hosts: rhel_hosts
become: true
tasks:
- name: Install python3 selinux bindings
ansible.builtin.dnf:
name:
- python3-libselinux
- python3-policycoreutils
state: present
Step 5: Re-run and verify the import now succeeds
ansible db-01 -i inventory.ini -m command -a "/usr/bin/python3 -c 'import selinux; print(\"ok\")'"
db-01 | CHANGED | rc=0 >>
ok
The original copy/template task now runs and can set file contexts.
Example Root Cause Analysis
A template task that deployed a config file worked on the old fleet but failed on newly provisioned RHEL 9 hosts:
fatal: [app-07]: FAILED! => {"msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren't installed"}
Step 1 confirms SELinux is on:
ansible app-07 -i inventory.ini -m command -a "getenforce"
Enforcing
Step 2 shows Ansible is pointed at a project venv:
"ansible_python_interpreter": "/opt/deploy-venv/bin/python3.11"
Step 3 confirms the venv cannot import selinux, even though the system Python can. The team had installed python3-libselinux via the base image — but into the system /usr/bin/python3.9, while playbooks used the /opt/deploy-venv interpreter that the RPM never touched.
Root cause: the SELinux bindings existed for the wrong interpreter. Because libselinux is a C-extension binding to a system library and is not reliably pip-installable, the durable fix was to point Ansible at the system interpreter for tasks that manage files:
# group_vars/rhel_hosts.yml
ansible_python_interpreter: /usr/bin/python3
with python3-libselinux ensured present. The template task then set the file’s SELinux context correctly and succeeded.
Prevention Best Practices
- Bake
python3-libselinux(andpython3-policycoreutilsforseboolean) into base images for any RHEL-family host that runs Ansible file modules. - Pin
ansible_python_interpreterdeliberately and make sure the SELinux bindings are installed for that interpreter — venvs do not inherit system C-extension bindings. - Add a bootstrap play that installs the bindings with
dnf/yumbefore anycopy/templatetask, so a fresh host self-heals on first run. - Match the package to the Python version:
python3-libselinuxfor Python 3,libselinux-pythonfor legacy Python 2 hosts. - Do not “fix” the error by disabling SELinux — that trades a one-package install for a real security regression; install the bindings instead.
- For a fleet where interpreter and SELinux state vary by host, the free incident assistant can help correlate which hosts need the bindings. See more in the Ansible guides.
Quick Command Reference
# Is SELinux actually active?
ansible <host> -i inventory.ini -m command -a "getenforce"
# Which interpreter does Ansible use on the target?
ansible <host> -i inventory.ini -m setup -a "filter=ansible_python_interpreter"
# Can THAT interpreter import selinux?
ansible <host> -i inventory.ini -m command -a "/usr/bin/python3 -c 'import selinux'"
# Install the bindings (Python 3 / RHEL family)
ansible <host> -i inventory.ini -b -m dnf \
-a "name=python3-libselinux,python3-policycoreutils state=present"
# Pin the interpreter that has the bindings (group_vars):
# ansible_python_interpreter: /usr/bin/python3
Conclusion
Aborting, target uses selinux but python bindings (libselinux-python) aren't installed means SELinux is enabled on the target but the Python interpreter Ansible uses cannot import the selinux bindings needed to manage file contexts. The usual root causes:
- The
python3-libselinuxpackage is not installed at all. - It is installed for a different interpreter than the one Ansible uses (common with venvs).
- The wrong package name for the target’s Python major version.
- SELinux was recently switched to enforcing/permissive on a host you assumed was disabled.
Confirm SELinux is on, find the exact interpreter with setup, prove the import fails for that interpreter, and install the matching libselinux bindings — never by disabling SELinux — to turn the abort into a clean run.
More Ansible prompts & error guides
Every Ansible AI prompt and troubleshooting guide, in one place.
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.