The Problem
You’ve double-checked your SSH keys and sudo rights, yet your Ansible playbook crashes immediately. The error message is blunt: sudo: sorry, you must have a tty to run sudo. This isn't a bug in your code. It’s a security gatekeeper on the remote host blocking non-interactive automation.
This usually happens when managing legacy Red Hat environments (RHEL 6 or CentOS 6). It also pops up in highly secured clusters where the policy forbids running sudo without a real interactive terminal session.
TL;DR: The Quick Fix
The most reliable solution is disabling the requiretty setting on the target server. Log into the remote machine, run visudo, and comment out this line:
# Defaults requiretty
If you cannot modify the server's security policy, try enabling SSH Pipelining in your local ansible.cfg to change how commands are streamed:
[ssh_connection]
pipelining = True
Detailed Root Cause
Linux kernels use pseudo-terminals (PTYs) for interactive sessions. Historically, distributions like RHEL 5 and 6 shipped with Defaults requiretty enabled in the /etc/sudoers file. This setting ensures that sudo only works if a user is physically or virtually 'typed' at a terminal.
Ansible prioritizes speed. By default, it executes modules by streaming them over SSH without allocating a PTY. This makes the automation faster but triggers the security check. When Ansible attempts to become: yes, the remote system sees a non-interactive stream instead of a TTY and kills the process instantly.
Modern security standards generally view requiretty as having low security value. Consequently, most modern distros like Ubuntu, Debian, and RHEL 7+ have removed this restriction entirely.
Fix Approach 1: Modifying the Sudoers File (Recommended)
Addressing the problem at the source is the cleanest route. You have two ways to apply this change safely using the visudo tool.
1. Disable it globally
Run sudo visudo on the target machine. Locate the requiretty line and prefix it with a # character.
# Find this line:
Defaults requiretty
# Change it to:
# Defaults requiretty
2. Disable it for the Ansible user
You might prefer keeping the policy for other users while exempting your automation account (e.g., ansible_user). Add this specific rule to the end of the file:
Defaults:ansible_user !requiretty
Fix Approach 2: Enabling SSH Pipelining
If you are managing 500+ legacy servers, manual edits aren't feasible. Enabling pipelining reduces the number of SSH operations required to run a module. This often bypasses the TTY requirement by changing how the command payload is delivered to the remote shell.
Edit your ansible.cfg file in your project root:
[ssh_connection]
pipelining = True
Note: Pipelining can speed up execution by 30% or more. However, if your sudo setup requires a password (rather than NOPASSWD), pipelining might cause the task to hang. Always test this in staging first.
Fix Approach 3: Forcing a TTY (The Last Resort)
You can trick the remote host by forcing Ansible to allocate a pseudo-terminal. This mimics a real user session. Use the -tt flag within your SSH arguments.
In your ansible.cfg:
[ssh_connection]
ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s -tt
Why this is a last resort: Forcing a TTY often breaks modules that expect clean data streams. TTYs can inject hidden control characters or wrap long lines of output, leading to unpredictable parsing errors in Ansible.
Verification: Confirming the Fix
Once you've applied a fix, run a quick ad-hoc command. This verifies that privilege escalation now works across your inventory:
ansible all -m shell -a "whoami" --become
If the command returns root for your hosts instead of the TTY error, the hurdle is cleared.
Summary
- The cause: A legacy
requirettysetting in/etc/sudoersblocks non-interactivesudocalls. - Best fix: Comment out
Defaults requirettyusingvisudo. - Scale fix: Enable
pipelining = Truein your Ansible configuration to streamline connections.

