AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible 'Destination Does Not Exist' Error: Fix Path Issues

By Luca Berton · Published 2024-01-01 · Category: troubleshooting

Fix Ansible destination does not exist error. Resolve missing parent directories, wrong paths, and permission issues for copy, template, and file modules.

Ansible 'Destination Does Not Exist' Error: Fix Path Issues

Introduction

Welcome to another episode of Ansible Pilot! I'm Luca Berton, and today we'll dive into troubleshooting Ansible, specifically focusing on the notorious "destination does not exist error." This error often occurs when attempting to download a file from a URL using Ansible, and it can be a stumbling block for many users. In this article, I'll walk you through the error, Playbooknstrate how to reproduce it, and provide a fix to ensure a smooth Ansible playbook execution.

See also: Ansible 'chgrp failed' Error: Fix Group Ownership Permission Issues

The destination does not exist Error

Let's start by examining the error through a live Playbook. Below is a simplified Ansible playbook (destinationdoesnotexist_error.yml) that attempts to download a file using the get_url module:

---
- name: Get_url module Playbook
  hosts: all
  become: false
  vars:
    myurl: "https://releases.ansible.com/ansible/ansible-2.9.25.tar.gz"
    mycrc: "sha256:https://releases.ansible.com/ansible/ansible-2.9.25.tar.gz.sha"
    mydest: "ansible-2.9.25.tar.gz"
  tasks:
    - name: Download file
      ansible.builtin.get_url:
        url: "{{ myurl }}"
        dest: "{{ mydest }}"
        checksum: "{{ mycrc }}"
        mode: '0644'

Upon execution, you might encounter the following error:

$ ansible-playbook -i inventory destinationdoesnotexist_error.yml

PLAY [Get_url module Playbook] ******************************************************************

TASK [Gathering Facts] ********************************************************************** ok: [demo.example.com]

TASK [Download file] ************************************************************************ fatal: [demo.example.com]: FAILED! => {"changed": false, "checksum_dest": null, "checksum_src": "574e24659f555fe370571167d3d44704671f1773", "dest": "ansible-2.9.25.tar.gz", "elapsed": 3, "msg": "Destination does not exist", "src": "/home/devops/.ansible/tmp/ansible-tmp-1640555219.326019-1431-267536126421544/tmpmx_ra0hd", "url": "https://releases.ansible.com/ansible/ansible-2.9.25.tar.gz"}

PLAY RECAP ********************************************************************************** demo.example.com : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0

The error message clearly indicates that the destination does not exist.

Reproducing and Fixing the Error

Reproducing the Error

To reproduce the error, we can use the provided playbook (destinationdoesnotexist_error.yml). This playbook attempts to download the Ansible archive into the home directory, resulting in the "destination does not exist" error.

Fixing the Error

Let's address the issue by modifying the playbook. In the fixed version (destinationdoesnotexist_fix.yml), we adjust the destination path to include the current directory:

---
- name: Get_url module Playbook
  hosts: all
  become: false
  vars:
    myurl: "https://releases.ansible.com/ansible/ansible-2.9.25.tar.gz"
    mycrc: "sha256:https://releases.ansible.com/ansible/ansible-2.9.25.tar.gz.sha"
    mydest: "ansible-2.9.25.tar.gz"
  tasks:
    - name: Download file
      ansible.builtin.get_url:
        url: "{{ myurl }}"
        dest: "./{{ mydest }}"
        checksum: "{{ mycrc }}"
        mode: '0644'

Now, when you execute this playbook, you should observe a successful download without encountering the "destination does not exist" error.

$ ansible-playbook -i inventory destinationdoesnotexist_fix.yml

PLAY [Get_url module Playbook] ******************************************************************

TASK [Gathering Facts] ********************************************************************** ok: [demo.example.com]

TASK [download file] ************************************************************************ changed: [demo.example.com]

PLAY RECAP ********************************************************************************** demo.example.com : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Verification

To confirm the success, log in to the target machine and check if the file has been downloaded to the specified directory:

$ ssh devops@demo.example.com
[devops@demo ~]$ ls -al
total 13964
drwx------. 4 devops wheel      140 Dec 26 21:47 .
...
-rw-r--r--. 1 devops wheel 14280306 Dec 26 21:47 ansible-2.9.25.tar.gz

See also: Ansible 'fatal: template error while templating string' Fix (Guide)

Conclusion

In this article, we explored the Ansible "destination does not exist" error, reproduced it in a live Playbook, and provided a fix. Now you have the knowledge to troubleshoot and overcome this common issue in your Ansible playbooks. If you found this tutorial helpful, consider subscribing for more Ansible tips and tricks. Happy automating!

The Fix: Create Directory First

# WRONG - fails if /opt/myapp/config/ doesn't exist
- ansible.builtin.copy:
    src: config.yml
    dest: /opt/myapp/config/config.yml

# CORRECT - create directory first - ansible.builtin.file: path: /opt/myapp/config state: directory owner: appuser mode: '0755' become: true

- ansible.builtin.copy: src: config.yml dest: /opt/myapp/config/config.yml owner: appuser become: true

See also: Ansible 'Missing Required Arguments' Error: Fix Missing Module Parameters

Common Scenarios

copy module

- file:
    path: /etc/myapp
    state: directory
  become: true

- copy: src: app.conf dest: /etc/myapp/app.conf become: true

template module

- file:
    path: /etc/nginx/sites-available
    state: directory
  become: true

- template: src: vhost.conf.j2 dest: /etc/nginx/sites-available/myapp.conf become: true

unarchive module

- file:
    path: /opt/myapp
    state: directory
    owner: deploy
  become: true

- unarchive: src: myapp-2.0.tar.gz dest: /opt/myapp become: true

Create Multiple Directories at Once

- name: Create app directory structure
  ansible.builtin.file:
    path: "{{ item }}"
    state: directory
    owner: appuser
    mode: '0755'
  loop:
    - /opt/myapp/config
    - /opt/myapp/logs
    - /opt/myapp/data
    - /opt/myapp/tmp
  become: true

Role Pattern

# roles/myapp/tasks/main.yml
- name: Create directories
  file:
    path: "{{ item }}"
    state: directory
    owner: "{{ myapp_user }}"
  loop: "{{ myapp_directories }}"
  become: true

- name: Deploy configs template: src: "{{ item.src }}" dest: "{{ item.dest }}" loop: "{{ myapp_config_files }}" become: true

Check Before Copy

- stat:
    path: /opt/myapp/config
  register: dir_check

- file: path: /opt/myapp/config state: directory when: not dir_check.stat.exists become: true

Windows Equivalent

- ansible.windows.win_file:
    path: C:\Program Files\MyApp\config
    state: directory

- ansible.windows.win_copy: src: config.xml dest: C:\Program Files\MyApp\config\config.xml

FAQ

Does file: state=directory create parent directories?

Yes — like mkdir -p, it creates all missing parent directories.

Why not just use creates or force?

Neither creates missing directories. The copy/template modules require the parent directory to exist — they only create the file itself.

Can I use dest: /opt/myapp/config/ (trailing slash)?

A trailing slash implies a directory. If it doesn't exist, Ansible still fails. Always create the directory explicitly.

The Error

fatal: [web1]: FAILED! => {"msg": "Destination directory /opt/myapp/config does not exist"}

Quick Fix

# Create parent directory first
- ansible.builtin.file:
    path: /opt/myapp/config
    state: directory
    mode: '0755'
  become: true

- ansible.builtin.copy: src: app.conf dest: /opt/myapp/config/app.conf become: true

Common Causes

Missing Parent Directory

# WRONG — /opt/myapp/ doesn't exist
- copy:
    src: app.conf
    dest: /opt/myapp/config/app.conf

# CORRECT — create directory first - file: path: /opt/myapp/config state: directory become: true

- copy: src: app.conf dest: /opt/myapp/config/app.conf become: true

Wrong Path

# Check if path exists
- stat:
    path: /opt/myapp
  register: app_dir

- debug: msg: "Directory exists: {{ app_dir.stat.exists }}"

Trailing Slash Confusion

# dest with trailing slash = directory (must exist!)
- copy:
    src: app.conf
    dest: /opt/myapp/config/   # Copies INTO this directory

# dest without trailing slash = full file path - copy: src: app.conf dest: /opt/myapp/config/app.conf # Creates this file

Create Full Directory Tree

- name: Create directory structure
  file:
    path: "{{ item }}"
    state: directory
    mode: '0755'
  loop:
    - /opt/myapp
    - /opt/myapp/bin
    - /opt/myapp/config
    - /opt/myapp/logs
  become: true

Modules Affected

| Module | Requires Parent Dir? | |--------|---------------------| | copy | Yes | | template | Yes | | get_url | Yes | | unarchive | Yes (dest) | | file: state=file | Yes | | file: state=directory | No (creates parents) |

FAQ

Why doesn't copy create directories?

By design — copy manages file content, not directory structure. Use file: state=directory for directory management. This separation follows Unix philosophy.

How to create directory only if needed?

file: state=directory is already idempotent — it creates if missing and does nothing if it exists. No need for extra checks.

Does this affect the controller or remote?

The error refers to the remote host path. The source path (src:) is on the controller.

Related Articles

Ansible become guidemanaging inventory in AnsibleAnsible role best practices

Category: troubleshooting

Watch the video: Ansible 'Destination Does Not Exist' Error: Fix Path Issues — Video Tutorial

Browse all Ansible tutorials · AnsiblePilot Home