Ansible - Resolve "Destination not writable"

"Destination not writable" is returned when attempting to create, copy, download or move a file to a directory that the user lacks the write permission. There are a number of different modules that are used to create, copy, download or move a file to a directory, such as:

As an example, let's say the file module is being used to create foo.txt in the /etc directory.

- name: "create foo.txt in the /etc directory"
    path: "/etc/foo.txt"
    state: "touch"


Typically, the /etc directory has the following ownership and permissions. Notice only root has the "w" (write) permission to this directory.

drwxr-xr-x. 124 root root 8192 Oct 15 05:59 /etc


Using native Linux commands, if a user other than root attempts to write to the /etc directory, "permission denied" would be returned.

[john.doe]$ touch /etc/foo.txt
touch: cannot touch ‘/etc/foo.txt’: Permission denied


Likewise, if John Doe (or any user other than root) were to invoke an Ansible playbook that attempted to create, copy, download or move a file to the /etc directory, "Destination not writable" would be returned.

TASKS [create foo.txt in the /etc directory]
fatal: []: FAILED! => {"changed": false, "checksum": "34949034fz73467b77cdc923aa747b", "msg": "Destination /etc not writable"}


Furthermore, the file module could be used to confirm that only root can write to the /etc directory.

- name: "get the stats of the '/etc' directory"
    path: "/etc"
  register: out

- name: "output the 'out' variable"
    msg: "{{ out }}"


Which should return something like this. Notice here the "writeable" is "false".

TASK [output the 'out' variable] 
ok: [] => {
    "msg": {
        "changed": false, 
        "failed": false, 
        "stat": {
            "atime": 1602763108.245787, 
            "attr_flags": "", 
            "attributes": [], 
            "block_size": 4096, 
            "blocks": 24, 
            "charset": "binary", 
            "ctime": 1602762950.0358446, 
            "dev": 64768, 
            "device_type": 0, 
            "executable": true, 
            "exists": true, 
            "gid": 0, 
            "gr_name": "root", 
            "inode": 69, 
            "isblk": false, 
            "ischr": false, 
            "isdir": true, 
            "isfifo": false, 
            "isgid": false, 
            "islnk": false, 
            "isreg": false, 
            "issock": false, 
            "isuid": false, 
            "mimetype": "inode/directory", 
            "mode": "0755", 
            "mtime": 1602762950.0358446, 
            "nlink": 124, 
            "path": "/etc", 
            "pw_name": "root", 
            "readable": true, 
            "rgrp": true, 
            "roth": true, 
            "rusr": true, 
            "size": 8192, 
            "uid": 0, 
            "version": "1862525523", 
            "wgrp": false, 
            "woth": false, 
            "writeable": false, 
            "wusr": true, 
            "xgrp": true, 
            "xoth": true, 
            "xusr": true


Be aware that a sort of "false positive" situation can occur. Let's say /tmp/foo.txt already exists, and foo.txt is owned by John Doe.

~]$ ls -l /tmp/foo.txt
-rw-r--r--. 1 john.doe  admins 1524 Oct 16 05:23 foo.txt


If Jane Doe attempts to create, copy, download or move foo.txt to /tmp/foo.txt, Jane may also get "Destination /etc not writable". For this reason, before you create, copy, download or move a file, it's a good practice to first determine if the file already exists.

- name: "store the statistics of /tmp/foo.txt in the 'foo' variable"
    path: "/tmp/foo.txt"
  register: foo


The fail module can now be used to cease execution of the playbook if /opt/example.txt does not exist.

- name: "fail when /tmp/foo.txt exists"
   msg: "/tmp/foo.txt already exists"
  when: "foo.stat.exists == true"


Assuming the target file does not already exist, there are a few solutions to "Destination not writeable":

  • create, copy, download or move a file to a directory that the is writeable, such as the /tmp directory
  • Invoke the playbook as root
  • Use "become" to become root - of course, this assumes that you have the root password


Add a Comment

We will never share your name or email with anyone. Enter your email if you would like to be notified when we respond to your comment.

Please enter 39972 in the box below so that we can be sure you are a human.


Web design by yours truely - me, myself, and I   |   |