# Buggy code
def setup_vault_secrets(
    loader,
    vault_ids,
    vault_password_files=None,
    ask_vault_pass=None,
    create_new_password=False,
):
    # list of tuples
    vault_secrets = []

    # Depending on the vault_id value (including how --ask-vault-pass / --vault-password-file create a vault_id)
    # we need to show different prompts. This is for compat with older Towers that expect a
    # certain vault password prompt format, so 'promp_ask_vault_pass' vault_id gets the old format.
    prompt_formats = {}

    vault_password_files = vault_password_files or []
    if C.DEFAULT_VAULT_PASSWORD_FILE:
        vault_password_files.append(C.DEFAULT_VAULT_PASSWORD_FILE)

    if create_new_password:
        prompt_formats["prompt"] = [
            "New vault password (%(vault_id)s): ",
            "Confirm vew vault password (%(vault_id)s): ",
        ]
    else:
        prompt_formats["prompt"] = ["Vault password (%(vault_id)s): "]
        # The format when we use just --ask-vault-pass needs to match 'Vault password:\s*?$'
        prompt_formats["prompt_ask_vault_pass"] = ["Vault password: "]

    vault_ids = CLI.build_vault_ids(vault_ids, vault_password_files, ask_vault_pass)

    for vault_id_slug in vault_ids:
        vault_id_name, vault_id_value = CLI.split_vault_id(vault_id_slug)
        if vault_id_value in ["prompt", "prompt_ask_vault_pass"]:
            # --vault-id some_name@prompt_ask_vault_pass --vault-id other_name@prompt_ask_vault_pass will be a little
            # confusing since it will use the old format without the vault id in the prompt
            if vault_id_name:
                prompted_vault_secret = PromptVaultSecret(
                    prompt_formats=prompt_formats[vault_id_value],
                    vault_id=vault_id_name,
                )
                prompted_vault_secret.load()
                vault_secrets.append((vault_id_name, prompted_vault_secret))
            else:
                # ie, we used --ask-vault-pass, so we need to use the old vault password prompt
                # format since Tower needs to match on that format.
                prompted_vault_secret = PromptVaultSecret(
                    prompt_formats=prompt_formats[vault_id_value],
                    vault_id=C.DEFAULT_VAULT_IDENTITY,
                )
                prompted_vault_secret.load()
                vault_secrets.append((C.DEFAULT_VAULT_IDENTITY, prompted_vault_secret))

            # update loader with new secrets incrementally, so we can load a vault password
            # that is encrypted with a vault secret provided earlier
            loader.set_vault_secrets(vault_secrets)
            continue

        # assuming anything else is a password file
        display.vvvvv("Reading vault password file: %s" % vault_id_value)
        # read vault_pass from a file
        file_vault_secret = get_file_vault_secret(
            filename=vault_id_value, vault_id_name=vault_id_name, loader=loader
        )
        file_vault_secret.load()
        if vault_id_name:
            vault_secrets.append((vault_id_name, file_vault_secret))
        else:
            vault_secrets.append((C.DEFAULT_VAULT_IDENTITY, file_vault_secret))

        # update loader with as-yet-known vault secrets
        loader.set_vault_secrets(vault_secrets)

    return vault_secrets


# Traceback (KeyError)
$ ansible-vault edit --ask-vault-pass host_vars/project/vault.yml -vvv
ansible-vault 2.4.0 (devel e8410c210d) last updated 2017/08/08 12:37:14 (GMT +100)
config file = None
configured module search path = [u'/home/jamie/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /home/jamie/ansible/lib/ansible
executable location = /home/jamie/ansible/bin/ansible-vault
python version = 2.7.12 (default, Nov 19 2016, 06:48:10) [GCC 5.4.0 20160609]
No config file found; using defaults
ERROR! Unexpected Exception, this is probably a bug: u'prompt_ask_vault_pass'
the full traceback was:

Traceback (most recent call last):
File "/home/jamie/ansible/bin/ansible-vault", line 106, in <module>
exit_code = cli.run()
File "/home/jamie/ansible/lib/ansible/cli/vault.py", line 180, in run
create_new_password=True)
File "/home/jamie/ansible/lib/ansible/cli/__init__.py", line 237, in setup_vault_secrets
prompted_vault_secret = PromptVaultSecret(prompt_formats=prompt_formats[vault_id_value],
KeyError: u'prompt_ask_vault_pass'

# Fixed code
def setup_vault_secrets(
    loader,
    vault_ids,
    vault_password_files=None,
    ask_vault_pass=None,
    create_new_password=False,
):
    # list of tuples
    vault_secrets = []

    # Depending on the vault_id value (including how --ask-vault-pass / --vault-password-file create a vault_id)
    # we need to show different prompts. This is for compat with older Towers that expect a
    # certain vault password prompt format, so 'promp_ask_vault_pass' vault_id gets the old format.
    prompt_formats = {}

    vault_password_files = vault_password_files or []
    if C.DEFAULT_VAULT_PASSWORD_FILE:
        vault_password_files.append(C.DEFAULT_VAULT_PASSWORD_FILE)

    if create_new_password:
        prompt_formats["prompt"] = [
            "New vault password (%(vault_id)s): ",
            "Confirm vew vault password (%(vault_id)s): ",
        ]
        # 2.3 format prompts for --ask-vault-pass
        prompt_formats["prompt_ask_vault_pass"] = [
            "New Vault password: ",
            "Confirm New Vault password: ",
        ]
    else:
        prompt_formats["prompt"] = ["Vault password (%(vault_id)s): "]
        # The format when we use just --ask-vault-pass needs to match 'Vault password:\s*?$'
        prompt_formats["prompt_ask_vault_pass"] = ["Vault password: "]

    vault_ids = CLI.build_vault_ids(vault_ids, vault_password_files, ask_vault_pass)

    for vault_id_slug in vault_ids:
        vault_id_name, vault_id_value = CLI.split_vault_id(vault_id_slug)
        if vault_id_value in ["prompt", "prompt_ask_vault_pass"]:
            # --vault-id some_name@prompt_ask_vault_pass --vault-id other_name@prompt_ask_vault_pass will be a little
            # confusing since it will use the old format without the vault id in the prompt
            if vault_id_name:
                prompted_vault_secret = PromptVaultSecret(
                    prompt_formats=prompt_formats[vault_id_value],
                    vault_id=vault_id_name,
                )
                prompted_vault_secret.load()
                vault_secrets.append((vault_id_name, prompted_vault_secret))
            else:
                # ie, we used --ask-vault-pass, so we need to use the old vault password prompt
                # format since Tower needs to match on that format.
                prompted_vault_secret = PromptVaultSecret(
                    prompt_formats=prompt_formats[vault_id_value],
                    vault_id=C.DEFAULT_VAULT_IDENTITY,
                )
                prompted_vault_secret.load()
                vault_secrets.append((C.DEFAULT_VAULT_IDENTITY, prompted_vault_secret))

            # update loader with new secrets incrementally, so we can load a vault password
            # that is encrypted with a vault secret provided earlier
            loader.set_vault_secrets(vault_secrets)
            continue

        # assuming anything else is a password file
        display.vvvvv("Reading vault password file: %s" % vault_id_value)
        # read vault_pass from a file
        file_vault_secret = get_file_vault_secret(
            filename=vault_id_value, vault_id_name=vault_id_name, loader=loader
        )
        file_vault_secret.load()
        if vault_id_name:
            vault_secrets.append((vault_id_name, file_vault_secret))
        else:
            vault_secrets.append((C.DEFAULT_VAULT_IDENTITY, file_vault_secret))

        # update loader with as-yet-known vault secrets
        loader.set_vault_secrets(vault_secrets)

    return vault_secrets