Solving the Ansible 'chdir failed: No such file or directory' Error

beginner🔧 Ansible2026-06-28| Ansible 2.9+, Linux (Ubuntu, CentOS, RHEL), macOS, Remote Target via SSH

Error Message

fatal: [host]: FAILED! => {"changed": false, "cmd": "make install", "msg": "chdir /opt/app/build failed: [Errno 2] No such file or directory: '/opt/app/build'"}
#ansible#devops#troubleshooting#linux#automation

The 2 AM Deployment Headache

We’ve all been there. You’re pushing a routine update, expecting a quick success message, but instead, your terminal spits out a wall of red text. You were trying to run a simple make install or a script, but Ansible couldn't find the directory it was supposed to work in. It’s a frustrating roadblock, especially when you're certain the folder should be there.

The error usually looks like this:

fatal: [host]: FAILED! => {"changed": false, "cmd": "make install", "msg": "chdir /opt/app/build failed: [Errno 2] No such file or directory: '/opt/app/build'"}

When this happens, Ansible is telling you that the chdir parameter in your shell or command module points to a path that doesn't exist on the remote host. This isn't a bug in your local setup. It's a missing state on the target server—perhaps a folder wasn't created, or a previous step failed without stopping the playbook.

Why is the Directory Missing?

Before you start hacking at the code, you need to know why the path is gone. In 90% of cases, it's one of these three culprits:

  • Silent Failures: A previous git clone or unarchive task failed (perhaps due to a 403 Forbidden or disk space issue) and didn't create the folder.
  • Path Confusion: You used a relative path like chdir: build, which Ansible tried to find relative to the SSH user's home directory (e.g., /home/ubuntu/build) instead of the intended system path.
  • Empty Variables: You’re using a variable like chdir: "{{ app_path }}", but the variable is undefined or accidentally set to an empty string.

Quick Debug: Check the Remote State

Don't guess. Run a quick ad-hoc command to see what the server sees:

ansible all -m shell -a "ls -ld /opt/app/build" -i inventory.ini

If the server returns ls: cannot access..., the folder is physically missing. If it returns the directory details, you likely have a permissions issue or a typo in your playbook variable.

The Solutions

1. Force the Directory to Exist

The most reliable fix is to use the file module right before your command. This ensures the directory exists regardless of what happened in previous steps. It’s a core principle of infrastructure as code: don't assume, enforce.

- name: Ensure the build directory is ready
  ansible.builtin.file:
    path: /opt/app/build
    state: directory
    mode: '0755'

- name: Run the installation
  ansible.builtin.command: make install
  args:
    chdir: /opt/app/build

2. Switch to Absolute Paths

Relative paths are a major source of 'No such file' errors. If your playbook runs as root, chdir: project looks in /root/project. If it runs as ec2-user, it looks in /home/ec2-user/project. Always use the full path, like /var/www/my-app/build, to keep your playbooks predictable.

3. Use the 'Creates' Argument for Safety

You can make your tasks smarter using creates. This tells Ansible: "Only run this command if this specific file is missing." It’s a great way to prevent errors and make your playbooks idempotent.

- name: Compile the application
  ansible.builtin.shell: ./configure && make
  args:
    chdir: /opt/app/src
    creates: /opt/app/src/Makefile

4. Handling Dynamic Deployments

If your paths change based on timestamps or Git hashes, ensure your variables are registered correctly. For example, if you're deploying to a folder named after today's date:

- name: Define the release path
  set_fact:
    rel_path: "/opt/releases/{{ ansible_date_time.date }}"

- name: Create the release folder
  ansible.builtin.file:
    path: "{{ rel_path }}"
    state: directory

- name: Initialize the app
  ansible.builtin.shell: python3 manage.py migrate
  args:
    chdir: "{{ rel_path }}"

Verifying the Fix

After updating your playbook, run it with the -v (verbose) flag. Look for the file module output. If it says "changed": true, it means the directory was indeed missing and Ansible fixed it for you. You can also run stat /opt/app/build on the remote server to verify the creation time and owner permissions (e.g., drwxr-xr-x).

Key Takeaways

  • Be Explicit: Never trust that a previous task created a folder. Use the file module to be certain.
  • Check Permissions: If the folder exists but you still get errors, the become_user might not have +x permissions to enter the parent directory.
  • Avoid Tilde (~): Don't use ~/build. Use /home/username/build to avoid ambiguity across different SSH users.

Related Error Notes