Fixing 'Could not find or access tasks file' in Ansible Roles

beginner🔧 Ansible2026-04-19| Ansible 2.9+, Linux (Ubuntu, CentOS, Debian), macOS.

Error Message

ERROR! Could not find or access '/path/to/tasks/setup.yml' on the Ansible Controller.
#include_tasks#import_tasks#roles#ansible-error

The Problem

Splitting logic into multiple files keeps your Ansible roles clean and manageable. You likely use include_tasks or import_tasks to pull these snippets into your main.yml. But even when the file is clearly sitting in your directory, Ansible sometimes throws a 'Could not find or access' error that halts your automation.

The error usually looks like this:

ERROR! Could not find or access '/path/to/tasks/setup.yml' on the Ansible Controller.

If we are using a role, the lookup is relative to the role's tasks/ directory. 
Make sure the file exists and is readable.

Why This Happens

Ansible follows a strict search hierarchy. When executing inside a role, the engine automatically searches for task files within that role's tasks/ subdirectory. Most failures stem from four specific oversights:

  • Redundant paths: Manually adding "tasks/" to a path when Ansible is already looking there.
  • Execution context: Running a playbook from a root directory that breaks relative path lookups.
  • Case sensitivity: Linux sees Setup.yml and setup.yml as two different files.
  • Broken symlinks: Using links that point to non-existent targets on the controller.

Step-by-Step Fixes

1. Remove Redundant Directory Prefixes

Imagine your file structure looks like this:

roles/
  my_app/
    tasks/
      main.yml
      setup.yml

Inside main.yml, you might mistakenly write:

# INCORRECT - This results in searching for tasks/tasks/setup.yml
- name: Include setup tasks
  include_tasks: tasks/setup.yml

Since Ansible already targets the tasks/ folder, adding it again creates a non-existent path. Fix this by using the filename alone:

# CORRECT
- name: Include setup tasks
  include_tasks: setup.yml

2. Use the {{ role_path }} Magic Variable

Hardcoding paths is risky in complex projects. If you are calling tasks from a different role or dealing with nested includes, use the role_path variable. This forces an absolute path on the controller, leaving no room for ambiguity.

- name: Include setup from current role safely
  include_tasks: "{{ role_path }}/tasks/setup.yml"

This approach is bulletproof when your playbooks live in non-standard directory structures.

3. Verify Extensions and Typos

Ansible won't guess your file extension. If your file is setup.yaml but your code references setup.yml, the task will fail immediately. Run a quick check to see exactly what is on the disk:

ls roles/my_app/tasks/

Standardize your project on one extension—either .yml or .yaml—to prevent these 3:00 AM debugging sessions.

4. Check Filesystem Permissions

Sometimes the file exists, but Ansible lacks the 'access' part of the error message. The user running ansible-playbook must have read permissions for the file and execute permissions for every parent directory. Fix permissions with these commands:

# Set standard read permissions (644) and directory access (755)
chmod 644 roles/my_app/tasks/setup.yml
chmod 755 roles/my_app/tasks/

5. Static vs. Dynamic Task Loading

While import_tasks and include_tasks look similar, they behave differently. import_tasks is static; it is processed when the playbook is first parsed. include_tasks is dynamic and evaluated at runtime. If your path uses a variable that isn't defined until the play starts, import_tasks will fail.

# This works because it evaluates during execution
- name: Dynamic include
  include_tasks: "{{ os_family }}_tasks.yml"

# This often fails if os_family is a gathered fact
- name: Static import
  import_tasks: "{{ os_family }}_tasks.yml"

Verification

To see exactly where Ansible is looking, run your playbook with triple verbosity. This reveals the search path logic in real-time:

ansible-playbook site.yml -vvv

Search the output for lines starting with searching for.... If you see a path like .../tasks/tasks/setup.yml, you've found your redundant directory bug.

Pro Tips

  • Avoid deep nesting: If a role requires more than 5 or 6 task files, it might be doing too much. Consider breaking it into two smaller, specialized roles.
  • Let the linter help: Use ansible-lint. It catches pathing issues and deprecated syntax before you even run the code.
  • The 1-second check: Always verify that your main.yml and sub-tasks are in the same tasks/ folder. 90% of these errors are simple placement mistakes.

Related Error Notes