ansible/ansible · error · AnsibleOptionsError
not a tty, editor cannot be opened
Error message
not a tty, editor cannot be opened
What it means
AnsibleOptionsError raised by VaultCLI.execute_create when stdout is not a TTY and --skip-tty-check was not passed. `ansible-vault create` needs to spawn $EDITOR interactively; without a terminal the editor cannot run, so Ansible aborts instead of hanging or corrupting the file. (Note the check is on stdout being a tty, so piping output also triggers it.)
Source
Thrown at lib/ansible/cli/vault.py:457
display.display("Reading ciphertext input from stdin", stderr=True)
for f in context.CLIARGS['args'] or ['-']:
self.editor.decrypt_file(f, output_file=context.CLIARGS['output_file'])
if sys.stdout.isatty():
display.display("Decryption successful", stderr=True)
def execute_create(self):
""" create and open a file in an editor that will be encrypted with the provided vault secret when closed"""
if len(context.CLIARGS['args']) != 1:
raise AnsibleOptionsError("ansible-vault create can take only one filename argument")
if sys.stdout.isatty() or context.CLIARGS['skip_tty_check']:
self.editor.create_file(context.CLIARGS['args'][0], self.encrypt_secret,
vault_id=self.encrypt_vault_id)
else:
raise AnsibleOptionsError("not a tty, editor cannot be opened")
def execute_edit(self):
""" open and decrypt an existing vaulted file in an editor, that will be encrypted again when closed"""
for f in context.CLIARGS['args']:
self.editor.edit_file(f)
def execute_view(self):
""" open, decrypt and view an existing vaulted file using a pager using the supplied vault secret """
for f in context.CLIARGS['args']:
# Note: vault should return byte strings because it could encrypt
# and decrypt binary files. We are responsible for changing it to
# unicode here because we are displaying it and therefore can make
# the decision that the display doesn't have to be precisely what
# the input was (leave that to decrypt instead)
plaintext = self.editor.plaintext(f)
self.pager(to_text(plaintext))
View on GitHub (pinned to 9cf16a4aca)
Solutions
- For automation, avoid create entirely: write the plaintext then `ansible-vault encrypt` it, or pipe to `ansible-vault encrypt_string --stdin-name`
- If a real terminal exists upstream (e.g. ssh), allocate it: ssh -t, docker exec -it
- As a last resort, --skip-tty-check lets it proceed, but the editor still needs to work non-interactively (e.g. EDITOR=true with content pre-supplied)
Example fix
# before (CI job) ansible-vault create secret.yml # fails: not a tty # after printf 'my_secret: value\n' > secret.yml ansible-vault encrypt --vault-id prompt secret.yml
Defensive patterns
Strategy: validation
Validate before calling
import sys, os
def create_is_safe() -> bool:
return sys.stdout.isatty() or bool(os.environ.get('ANSIBLE_VAULT_SKIP_TTY_CHECK'))
if not create_is_safe():
# non-interactive: write plaintext, then encrypt
pass Prevention
- Never use `ansible-vault create` in automation; write-then-encrypt instead
- Allocate a TTY (ssh -t, docker exec -it) for interactive create sessions
When it happens
Trigger: Running `ansible-vault create f.yml` inside CI, cron, a non-interactive SSH session without -t, or with output piped/redirected, without --skip-tty-check.
Common situations: Automation/CI attempts to use `create`; docker exec without -t; nohup'd scripts. Also $EDITOR unset or nonfunctional in minimal environments.
Related errors
- '%s' is not a valid vault id. The character ';' is not allow
- At most one input file may be used with the --output option
- The --prompt option is not supported if also reading input f
- A vault password is required to use Ansible's Vault
- The vault-ids %s are available to encrypt. Specify the vault
AI-assisted analysis of ansible/ansible@9cf16a4aca (2026-08-15).
Data as JSON: /api/errors/14cb9646c65cd630.
Report an issue: GitHub.