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.

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 guide • managing inventory in Ansible • Ansible role best practicesCategory: troubleshooting
Watch the video: Ansible 'Destination Does Not Exist' Error: Fix Path Issues — Video Tutorial