The Problem

Your playbook uses import_tasks to statically include task files, but it fails at parse time:

bash
ERROR! Could not locate file in lookup: tasks/required.yml

Or:

bash
ERROR! Error while reading file tasks/vars.yml: 'my_var' is undefined

Or when using variables in the filename:

bash
ERROR! 'task_file' is undefined

Unlike include_tasks, import_tasks errors occur at parse time, before any tasks run.

Why This Happens

import_tasks errors occur because:

File not found at parse time - Ansible validates imports before running tasks.

Variables in filename - import_tasks can't use variables (parse-time only).

Undefined variables in imported file - Variables must exist when playbook is parsed.

Path resolution issues - Wrong relative path to task file.

Task file syntax errors - Invalid YAML in the imported file.

Understanding import_tasks

import_tasks statically includes tasks at playbook parse time:

```yaml # main.yml - hosts: webservers tasks: - import_tasks: tasks/setup.yml

# tasks/setup.yml is parsed when main.yml is parsed # All tasks become part of main.yml before execution ```

Key differences from include_tasks: - Parse-time evaluation (not runtime) - Cannot use variables in filename - Faster execution (pre-processed) - Tasks inherit play context directly

Diagnosing the Issue

Check file exists:

bash
ls -la tasks/setup.yml
cat tasks/setup.yml

Validate playbook syntax:

bash
ansible-playbook playbook.yml --syntax-check

Check for variable usage in import:

bash
grep -n "import_tasks.*{{" playbook.yml
# This pattern indicates problematic variable usage

The Fix

Fix 1: Use Static Filename Only

import_tasks requires static filenames:

```yaml # WRONG - variable in filename (fails at parse time) - import_tasks: "tasks/{{ task_type }}.yml" # Error: task_type undefined at parse time

# CORRECT - static filename only - import_tasks: tasks/setup.yml ```

For dynamic filenames, use include_tasks instead:

yaml
# Use include_tasks for dynamic includes
- include_tasks: "tasks/{{ task_type }}.yml"
  when: task_type is defined

Fix 2: Fix File Path Issues

Use correct relative paths:

yaml
# playbook.yml in /ansible/playbooks/
- import_tasks: ../tasks/setup.yml  # Relative to playbook

Use playbook_dir for reliable paths:

yaml
- import_tasks: "{{ playbook_dir }}/tasks/setup.yml"
# playbook_dir is defined at parse time, safe for import

Verify file location:

bash
# From playbook directory
cat tasks/setup.yml
ansible-playbook playbook.yml --syntax-check

Fix 3: Handle Variables in Imported Files

Variables must be defined when file is imported:

```yaml # WRONG - variable undefined at parse time - hosts: webservers tasks: - import_tasks: tasks/config.yml # config.yml uses app_port which isn't defined

# tasks/config.yml - name: Configure template: src: app.conf.j2 dest: /etc/app.conf # Uses {{ app_port }} in template ```

yaml
# CORRECT - define vars before import
- hosts: webservers
  vars:
    app_port: 8080
  tasks:
    - import_tasks: tasks/config.yml

Fix 4: Task File Syntax Validation

Check imported file syntax separately:

bash
ansible-playbook tasks/setup.yml --syntax-check

Or validate all YAML:

bash
yamllint tasks/*.yml

Fix 5: Import Tasks with Tags

Tags work with import_tasks:

```yaml - import_tasks: tasks/setup.yml tags: - setup - install

# All tasks in setup.yml inherit these tags ```

Run specific imports:

bash
ansible-playbook playbook.yml --tags setup

Fix 6: Conditional Import Limitations

import_tasks doesn't support runtime conditions:

yaml
# WRONG - condition doesn't skip import at parse time
- import_tasks: tasks/production.yml
  when: env == 'production'
# File is still imported at parse time, just tasks skipped later

For true conditional imports, use include_tasks:

yaml
- include_tasks: tasks/production.yml
  when: env == 'production'
# File only included if condition is true at runtime

Fix 7: Import vs Include Comparison

When to use each:

```yaml # import_tasks - for static, predictable includes - import_tasks: tasks/common.yml # Always included, known file # Benefits: # - Faster (pre-processed) # - Tasks show in --list-tasks # - Better for roles

# include_tasks - for dynamic, conditional includes - include_tasks: "tasks/{{ os_family }}.yml" # Benefits: # - Dynamic filenames # - Runtime evaluation # - Can loop over includes ```

Fix 8: Import in Roles

Role task imports use import_tasks:

```yaml # roles/myrole/tasks/main.yml - import_tasks: install.yml - import_tasks: configure.yml - import_tasks: service.yml

# All imported at role parse time ```

For role task files with variables:

```yaml # Use include_vars first if tasks need vars - include_vars: "{{ item }}" loop: - defaults.yml - vars.yml

  • import_tasks: configure.yml
  • `

Fix 9: Handlers Import

Import handlers statically:

```yaml - hosts: webservers tasks: - import_tasks: tasks/main.yml

handlers: - import_tasks: handlers/main.yml ```

Verifying the Fix

Test import_tasks:

```yaml # test_import.yml - hosts: localhost gather_facts: no vars: test_var: imported tasks: - import_tasks: tasks/test_sub.yml

# tasks/test_sub.yml (create this file) - name: Imported task debug: msg: "test_var is {{ test_var }}" ```

Validate syntax:

bash
ansible-playbook test_import.yml --syntax-check

List all tasks (imports show):

bash
ansible-playbook test_import.yml --list-tasks
# Imported tasks appear in list

Run:

bash
ansible-playbook test_import.yml -v

Prevention

Create pre-flight validation:

bash
# Script to validate imports before running
#!/bin/bash
for playbook in playbooks/*.yml; do
  echo "Checking $playbook"
  ansible-playbook "$playbook" --syntax-check || exit 1
done

Use ansible-lint:

bash
ansible-lint playbook.yml
# Catches many import issues