Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Ansible By James Joyner IV · · 10 min read

Ansible Error Guide: 'MODULE FAILURE' (module failed to execute / Python interpreter)

Fix Ansible's MODULE FAILURE error: diagnose missing or wrong Python interpreter, ansible_python_interpreter, stray stdout on the host, and modules failing to execute.

  • #ansible
  • #troubleshooting
  • #errors
  • #python

Overview

MODULE FAILURE means Ansible shipped a module to the remote host, tried to run it, but the module never returned valid JSON. Almost every Ansible module is a Python program executed on the target; if Python is missing, the wrong version, or something prints extra text to stdout (corrupting the JSON Ansible parses), the wrapper reports MODULE FAILURE and shows the corrupted output.

You will see it like this:

fatal: [web-01]: FAILED! => {"changed": false, "module_stderr": "/bin/sh: 1: /usr/bin/python: not found\n", "module_stdout": "", "msg": "The module failed to execute correctly, you probably need to set the interpreter.\nSee stdout/stderr for the exact error", "rc": 127}

The diagnostic gold is in module_stderr / module_stdout. python: not found and rc: 127 means no interpreter at the expected path. A traceback means Python ran but errored. Stray text before the JSON (a banner, a .bashrc echo) means valid output got polluted.

Symptoms

  • Tasks fail with The module failed to execute correctly, you probably need to set the interpreter.
  • module_stderr shows python: not found, command not found, or a traceback.
  • rc: 127 (command not found) or a Python traceback in the output.
  • The raw/ping module works but real modules fail (transport is fine; Python is the issue).
ansible web-01 -i inventory.ini -m setup
web-01 | FAILED! => {
    "module_stderr": "/bin/sh: 1: /usr/bin/python: not found\n",
    "msg": "The module failed to execute correctly, you probably need to set the interpreter.",
    "rc": 127
}

Common Root Causes

1. No Python interpreter at the discovered path

Minimal images (some container bases, fresh distros) ship without /usr/bin/python or /usr/bin/python3. Ansible’s interpreter discovery picks a path that does not exist.

ansible web-01 -i inventory.ini -m raw -a 'command -v python3 python 2>/dev/null; ls -l /usr/bin/python*'
web-01 | CHANGED | rc=0 >>
ls: cannot access '/usr/bin/python*': No such file or directory

Install Python (via raw, which needs no Python):

ansible web-01 -i inventory.ini -m raw -a 'apt-get update && apt-get install -y python3' -b

2. ansible_python_interpreter points at the wrong path

An inventory/group_var sets ansible_python_interpreter to a path that is absent on this host.

ansible-inventory -i inventory.ini --host web-01 | grep python_interpreter
"ansible_python_interpreter": "/usr/bin/python"

If the host only has /usr/bin/python3, every module fails with python: not found. Fix the var or use auto-discovery.

3. Stray output on the remote shell corrupts the JSON

A .bashrc/.profile that echoes text, a login banner, or an MOTD prints before the module’s JSON, so Ansible cannot parse it.

"module_stdout": "Welcome to web-01!\n{\"changed\": false, ...}",
"msg": "MODULE FAILURE\nSee stdout/stderr for the exact error",
ansible web-01 -i inventory.ini -m raw -a 'echo MARKER; grep -RIl echo ~/.bashrc ~/.profile 2>/dev/null'

Any text before { in module_stdout is the culprit.

4. Wrong Python version / missing stdlib for the module

The interpreter exists but is too old, or a slimmed Python lacks a stdlib module the Ansible module imports.

ansible web-01 -i inventory.ini -m raw -a '/usr/bin/python3 -c "import sys, json, platform; print(sys.version)"'
Traceback (most recent call last):
  ModuleNotFoundError: No module named 'json'

A Python without json/platform cannot run Ansible modules.

5. Disk full or no temp dir on the remote host

Ansible copies the module into a temp dir (~/.ansible/tmp). If the filesystem is full or the dir is not writable, the module cannot be written/executed.

ansible web-01 -i inventory.ini -m raw -a 'df -h /tmp ~; touch ~/.ansible/tmp/.t 2>&1'
/dev/sda1   20G  20G   0  100% /
touch: cannot touch '/home/deploy/.ansible/tmp/.t': No space left on device

6. SELinux / noexec on the tmp dir

A noexec mount or SELinux denial on the temp directory blocks executing the staged module.

ansible web-01 -i inventory.ini -m raw -a 'mount | grep -E "/tmp|/home"; ausearch -m avc -ts recent 2>/dev/null | tail -3'
/dev/sda3 on /tmp type ext4 (rw,noexec,nosuid)

A noexec /tmp requires pointing remote_tmp at an executable path.

Diagnostic Workflow

Step 1: Read module_stderr / module_stdout

ansible web-01 -i inventory.ini -m setup 2>&1 | grep -E 'module_stderr|module_stdout|rc'

python: not found + rc: 127 -> interpreter. A traceback -> Python error. Text before { -> polluted stdout.

Step 2: Confirm Python with the raw module (no Python needed)

ansible web-01 -i inventory.ini -m raw -a 'command -v python3 python; ls -l /usr/bin/python*'

This works even when modules fail, and tells you exactly which interpreters exist.

Step 3: Check the configured interpreter vs. reality

ansible-inventory -i inventory.ini --host web-01 | grep python_interpreter

Compare the configured path to what Step 2 found on the host.

Step 4: Rule out stray stdout and tmp/exec problems

ansible web-01 -i inventory.ini -m raw -a 'echo START; df -h ~ /tmp; mount | grep -E "/tmp|/home"'

Any text the shell emits before START, a full disk, or a noexec tmp each break module execution.

Step 5: Set the correct interpreter (or install Python) and re-test

ansible web-01 -i inventory.ini -m setup \
  -e 'ansible_python_interpreter=/usr/bin/python3'

Once setup returns facts, bake the interpreter into inventory/group_vars.

Example Root Cause Analysis

A new batch of Debian 12 minimal cloud images is added to inventory. Every module fails:

fatal: [web-12]: FAILED! => {"module_stderr": "/bin/sh: 1: /usr/bin/python: not found\n", "rc": 127, "msg": "The module failed to execute correctly, you probably need to set the interpreter."}

ansible -m ping also fails the same way, but raw works:

ansible web-12 -i inventory.ini -m raw -a 'ls -l /usr/bin/python*'
lrwxrwxrwx 1 root root 10 /usr/bin/python3 -> python3.11

Only /usr/bin/python3 exists — there is no /usr/bin/python. Checking inventory:

ansible-inventory -i inventory.ini --host web-12 | grep python_interpreter
"ansible_python_interpreter": "/usr/bin/python"

A legacy group_var hard-codes /usr/bin/python, which these modern images do not provide. The wrong interpreter path is the root cause — the host has Python 3, just not at the configured path.

Fix: point the group at python3 (or let Ansible auto-discover):

# group_vars/web.yml
ansible_python_interpreter: /usr/bin/python3
ansible web-12 -i inventory.ini -m ping
web-12 | SUCCESS => {"changed": false, "ping": "pong"}

Prevention Best Practices

  • Set ansible_python_interpreter: auto_silent (or an explicit /usr/bin/python3) in group_vars so discovery never lands on a missing legacy path.
  • Bake Python 3 into your base images / cloud-init so freshly provisioned hosts are immediately manageable; use the raw module only for the bootstrap install.
  • Keep login shells quiet for the automation user — no echo in .bashrc/.profile and suppress MOTD — so module JSON is never polluted.
  • Mount /tmp executable (or set remote_tmp to an exec-capable path) and alert on disk-full conditions, since both break module staging.
  • Run ansible all -m ping after adding hosts or images; it surfaces interpreter problems before a real play does.
  • For sorting a wave of MODULE FAILURE output by cause across many new hosts, the free incident assistant can cluster them. See more in the Ansible guides.

Quick Command Reference

# Read the real error
ansible <host> -i inventory.ini -m setup 2>&1 | grep -E 'module_stderr|module_stdout|rc'

# Which Python exists? (raw needs no Python)
ansible <host> -i inventory.ini -m raw -a 'command -v python3 python; ls -l /usr/bin/python*'

# What interpreter is configured?
ansible-inventory -i inventory.ini --host <host> | grep python_interpreter

# Disk / exec / stray-output checks
ansible <host> -i inventory.ini -m raw -a 'echo START; df -h ~ /tmp; mount | grep -E "/tmp|/home"'

# Bootstrap Python on a minimal host
ansible <host> -i inventory.ini -m raw -a 'apt-get update && apt-get install -y python3' -b

# Override the interpreter for a run
ansible <host> -i inventory.ini -m ping -e 'ansible_python_interpreter=/usr/bin/python3'

Conclusion

MODULE FAILURE means a module never returned parseable JSON — usually a Python problem on the remote host. The detail is in module_stderr/module_stdout. The usual root causes:

  1. No Python interpreter at the discovered/expected path (rc: 127).
  2. ansible_python_interpreter set to a path the host lacks.
  3. Login banners or .bashrc echoes polluting the module’s stdout.
  4. A Python version too old, or missing stdlib modules.
  5. A full disk or unwritable ~/.ansible/tmp.
  6. A noexec/SELinux-restricted temp dir blocking execution.

Read the stderr, confirm the interpreter with raw, and align ansible_python_interpreter with reality (or install Python via raw) — that resolves the overwhelming majority of MODULE FAILURE cases.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

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.