AnsibleXLV · Debugging and TroubleshootingDebugging and Troubleshooting
Verbosity is a disclosure decision
What you'll learn
- State what each verbosity level from -v to -vvvv adds to the output
- Recognise that module arguments and results are disclosed from -v onwards
- Enable ssh CLI debugging explicitly rather than assuming -vvvv provides it
- Decide what must be redacted before verbose output leaves your terminal
Prerequisites
Verified against ansible-core 2.21.x · ansible (community package) 14.x · Python (controller) 3.12+ · ansible-lint 26.x · Molecule 26.x · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL / Rocky / AlmaLinux 9.x · 2026-08-11
Adding -v to a command feels like a diagnostic decision. It is also a
disclosure decision, and the second one is the one that gets people
into trouble, because verbose output does not stay in the terminal. It
goes into scrollback, into tmux history, into the CI job log, into the
ticket, into the chat channel, into the incident review document.
Everything in this part is about reading Ansible output. This lesson comes first because it establishes what you are allowed to paste.
What each level adds
Measured on ansible-core 2.21.3 with the same two-task play against
one host:
| Level | Output lines | What it adds |
|---|---|---|
| (none) | 12 | Task banners, per-host status words, the recap |
-v | 13 | The full module result as JSON, on one line per host |
-vv | 29 | Version banner, config file in effect, callback selection, task path: for every task |
-vvv | 73 | Inventory parsing, connection trace (ESTABLISH, EXEC, PUT), which module file was used, result JSON pretty-printed |
-vvvv | 83 | Plugin loading trace and a dump of the effective CLI and config: connection, become_method, tags, inventory, forks |
The upstream help text is worth quoting because it sets the expectation most people work from:
Adding multiple
-vwill increase the verbosity, the builtin plugins currently evaluate up to-vvvvvv. A reasonable level to start is-vvv, connection debugging might require-vvvv.
-vvv as a starting point is good advice: it is the first level that
shows you the connection sequence and the pretty-printed result
together, which is what most diagnosis needs.
The disclosure happens at -v, not at -vvvv
This is the finding worth changing your habits over. The common belief
is that -vvvv is the dangerous one. Verified on 2.21.3:
$ ansible-playbook -i inv.ini leak.yml -vTASK [A task that receives the secret as a module argument] ********************
ok: [lh] => {"changed": false, "changed_when_result": false, "cmd": ["/bin/echo",
"connecting", "with", "REPLACE_ME_NOT_A_REAL_SECRET"], "delta": "0:00:00.003179",
"msg": "", "rc": 0, "stderr": "", "stdout": "connecting with
REPLACE_ME_NOT_A_REAL_SECRET", "stdout_lines": ["connecting with
REPLACE_ME_NOT_A_REAL_SECRET"]}
TASK [The same task with no_log] ***********************************************
ok: [lh] => {"censored": "the output has been hidden due to the fact that
'no_log: true' was specified for this result", "changed": false}One -v. The secret appears twice — once in the cmd array that
records the module arguments, once in stdout.
The practical rule follows directly: do not reach for -v on a play
that handles secrets without knowing which tasks are no_log. Reach
for -vvv on a reproduction you have constructed with fake values.
-vvvv and the myth of automatic SSH debugging
Folklore says -vvvv gives you ssh -vvv. On ansible-core 2.21.3 it
does not.
$ ansible-playbook -i inv.ini one.yml -vvvv<192.0.2.11> ESTABLISH SSH CONNECTION FOR USER: None
<192.0.2.11> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s
-o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,
gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10
-o 'ControlPath="/home/ops/.ansible/cp/a87e32107b"' -o NumberOfPasswordPrompts=1
192.0.2.11 '/bin/sh -c '"'"'echo ~'"'"''
<192.0.2.11> (255, b'', b'ssh: connect to host 192.0.2.11 port 22: Connection
timed out')SSH CLI verbosity is a separate, explicit option on the ssh connection
plugin, and it defaults to 0:
$ ansible-doc -t connection ssh | grep -A 10 '^ verbosity' verbosity Requested verbosity level for the SSH CLI.
set_via:
env:
- name: ANSIBLE_SSH_VERBOSITY
ini:
- key: verbosity
section: ssh_connection
vars:
- name: ansible_ssh_verbosity
default: 0
type: int$ ANSIBLE_SSH_VERBOSITY=3 ansible-playbook -i inv.ini one.yml -vvv<192.0.2.11> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s ...
<192.0.2.11> (255, b'', b'debug1: OpenSSH_10.2p1, OpenSSL 3.5.5
debug1: Reading configuration data /etc/ssh/ssh_config
debug2: resolve_canonicalize: hostname 192.0.2.11 is address
debug1: auto-mux: Trying existing master at "/home/ops/.ansible/cp/a87e32107b"
debug1: Control socket does not exist
debug3: ssh_connect_direct: entering
debug1: Connecting to 192.0.2.11 [192.0.2.11] port 22.
debug1: connect to address 192.0.2.11 port 22: Connection timed out')--diff is a separate disclosure decision
--diff prints the content a file module would write. On a rendered
template, that is the rendered file — including every credential the
template interpolated.
It is the best configuration review surface Ansible has, and it is a disclosure of file contents by definition. The two facts are the same fact. Use it deliberately, and never in a pipeline whose output is readable by more people than the file is.
Before you paste
The checklist that belongs next to your keyboard:
| Check | Why |
|---|---|
Any cmd or module_args in the output? | Module arguments are printed from -v |
Any stdout from a command that echoed a value? | The command output is in the result too |
Any SSH: EXEC line? | Usernames, bastion addresses, key paths, ports |
Any --diff hunk? | File contents, verbatim |
Any ansible-config dump output? | Vault password file paths, log paths, custom plugin paths |
| Where is this going? | A ticket, a chat channel and a CI log all have different audiences and different retention |
Knowledge check
Knowledge check · 4 questions
Q1. At which verbosity level does a password passed as a module argument first appear in the output?
Q2. On ansible-core 2.21.3, OpenSSH debug output requires setting the ssh connection plugin verbosity option explicitly — adding further -v flags to ansible-playbook does not produce it.
Q3. Which of these disclose material that should be redacted before verbose output goes into a shared ticket? Select all that apply.
Q4. One host in a 300-host group fails with a connection error. What is the least damaging way to get OpenSSH debug output for it?
Passing score: 75%. Answers are checked in this browser.