Cách sửa lỗi Ansible: 'Invalid data passed to loop', yêu cầu một danh sách nhưng nhận được <class 'dict'>

beginner🔧 Ansible2026-07-24| Ansible 2.5+ chạy trên bất kỳ bản phân phối Linux nào (Ubuntu, RHEL, Debian) hoặc macOS.

Error Message

Invalid data passed to 'loop', it requires a list, got <class 'dict'>
#ansible#devops#troubleshooting#yaml

Hiểu về lỗi này

Bạn đang chạy một playbook để triển khai 15 Nginx virtual host, và mọi thứ có vẻ ổn cho đến khi task gặp trở ngại. Ansible dừng đột ngột và thông báo lỗi cụ thể này:

Invalid data passed to 'loop', it requires a list, got <class 'dict'>

Ansible đang thông báo rất chính xác. Từ khóa loop, vốn trở thành tiêu chuẩn từ phiên bản 2.5, yêu cầu nghiêm ngặt một danh sách YAML (một mảng). Nếu bạn truyền vào một dictionary (từ điển) — một tập hợp các cặp key-value nằm trong dấu ngoặc nhọn — task sẽ thất bại ngay lập tức. Nó giống như việc cố gắng nhét một khối vuông vào một cái lỗ tròn vậy.

Tại sao điều này xảy ra

Phần lớn thời gian, trở ngại này xảy ra do cách dữ liệu được cấu trúc hoặc thu thập. Dưới đây là ba nguyên nhân phổ biến nhất:

  • Sử dụng Dictionary trực tiếp: Bạn đã định nghĩa một biến dưới dạng dictionary nhưng lại cố gắng lặp qua nó như thể đó là một danh sách đơn giản.
  • Các biến đã đăng ký (Registered Variables): Bạn đã thu thập đầu ra của một module như find, nhưng bạn lại cố gắng lặp qua toàn bộ đối tượng kết quả thay vì danh sách các tệp bên trong nó.
  • Lỗi cú pháp YAML: Việc thiếu một dấu gạch ngang (-) trong tệp biến có thể vô tình biến một danh sách thành một dictionary.

Các bước khắc phục

Kịch bản 1: Chuyển đổi Dictionary ngay lập tức

Giả sử bạn có một danh sách người dùng được định nghĩa trong vars/main.yml như sau:

# vars/main.yml
users:
  alice: 
    uid: 1001
    shell: /bin/bash
  bob:
    uid: 1002
    shell: /bin/zsh

Nếu bạn cố gắng sử dụng loop: "{{ users }}", Ansible sẽ thấy một dictionary và báo lỗi. Cách khắc phục là sử dụng filter dict2items. Nó sẽ định dạng lại dictionary của bạn thành một danh sách mà Ansible có thể xử lý được.

# Task đã được sửa lại
- name: Tạo người dùng từ một dictionary
  ansible.builtin.user:
    name: "{{ item.key }}"
    uid: "{{ item.value.uid }}"
    shell: "{{ item.value.shell }}"
  loop: "{{ users | dict2items }}"

Kịch bản 2: Điều hướng các biến đã đăng ký

Đây là một cái bẫy kinh điển khi sử dụng các module find hoặc stat. Các module này trả về một dictionary khổng lồ chứa metadata, dấu thời gian và mã trạng thái. Danh sách thực tế mà bạn muốn thường nằm sâu hơn một cấp.

# Cách làm SAI
- name: Tìm các tệp log cũ
  ansible.builtin.find:
    paths: /var/log/nginx
    patterns: "*.log.gz"
  register: found_logs

- name: Dọn dẹp log
  ansible.builtin.file:
    path: "{{ item.path }}"
    state: absent
  loop: "{{ found_logs }}" # Lệnh này sẽ lỗi!

Cách khắc phục: Bạn phải trỏ vòng lặp vào thuộc tính files. Đó là nơi chứa danh sách thực sự.

# Cách làm ĐÚNG
- name: Dọn dẹp log
  ansible.builtin.file:
    path: "{{ item.path }}"
    state: absent
  loop: "{{ found_logs.files }}" # Trỏ vào danh sách cụ thể

Kịch bản 3: Phát hiện lỗi định dạng YAML

YAML rất nhạy cảm. Nếu bạn quên một dấu gạch ngang, cấu trúc dữ liệu của bạn sẽ thay đổi hoàn toàn. Hãy xem sự so sánh này:

# Sai: Đây là một Dictionary
my_packages:
  git: present
  vim: present

# Đúng: Đây là một Danh sách
my_packages:
  - git
  - vim

Kiểm tra các tệp biến của bạn. Nếu loop của bạn trỏ đến my_packages, hãy đảm bảo mọi mục đều bắt đầu bằng một dấu gạch ngang. Nếu không có những dấu gạch ngang đó, Ansible sẽ hiểu đó là một dictionary và kích hoạt lỗi.

Các bước xác minh

Bạn không chắc mình đang xử lý kiểu dữ liệu nào? Hãy sử dụng module debug và filter type_debug để kiểm tra các biến của bạn ngay khi đang chạy. Nó giúp tiết kiệm rất nhiều công sức đoán mò.

- name: Kiểm tra kiểu dữ liệu
  ansible.builtin.debug:
    msg: "Kiểu biến là {{ users | type_debug }}"

- name: Xác minh việc chuyển đổi
  ansible.builtin.debug:
    msg: "Sau khi dùng filter, kiểu là {{ (users | dict2items) | type_debug }}"

Nếu đầu ra hiển thị list, bạn đã sẵn sàng.

Mẹo thực tế để thành công

Việc hình dung YAML có thể khó khăn khi các playbook ngày càng lớn. Khi gặp bế tắc, tôi thường sử dụng một công cụ chuyển đổi YAML sang JSON. JSON chặt chẽ hơn nhiều với các dấu ngoặc vuông và ngoặc nhọn, giúp bạn dễ dàng nhận thấy mình đã tạo ra một Object (Dictionary) hay một Array (List).

Một mẹo cuối cùng: hãy chạy playbook của bạn với tham số -v. Ansible sẽ in cấu trúc JSON đầy đủ của các biến đã đăng ký. Điều này cho phép bạn thấy chính xác key nào đang giữ danh sách bạn cần cho vòng lặp mà không cần phải đoán tên thuộc tính.

Related Error Notes