Skip to main content
RunBook Academy

AnsibleXLV · Debugging and TroubleshootingDebugging and Troubleshooting

Verbosity is a disclosure decision

Advanced⏱ ~24 minansible-playbook

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

Not yet marked complete on this device.

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:

LevelOutput linesWhat it adds
(none)12Task banners, per-host status words, the recap
-v13The full module result as JSON, on one line per host
-vv29Version banner, config file in effect, callback selection, task path: for every task
-vvv73Inventory parsing, connection trace (ESTABLISH, EXEC, PUT), which module file was used, result JSON pretty-printed
-vvvv83Plugin 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 -v will 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:

Read-only / Safea secret in a module argument, at the very first verbosity level — executed on 2.21.3
$ ansible-playbook -i inv.ini leak.yml -v
TASK [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.

Read-only / Safe-vvvv against an unreachable host, showing the ssh command line — executed on 2.21.3
$ 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:

Read-only / Safethe ssh connection plugin verbosity option — read from ansible-doc on 2.21.3
$ 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
Read-only / Safeasking for ssh debugging explicitly — executed on 2.21.3
$ 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:

CheckWhy
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

  1. Q1. At which verbosity level does a password passed as a module argument first appear in the output?

  2. 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.

  3. Q3. Which of these disclose material that should be redacted before verbose output goes into a shared ticket? Select all that apply.

  4. 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.