TL;DR — Sửa nhanh
Chín trong mười trường hợp, lỗi này xuất phát từ một trong hai nguyên nhân:
- Giá trị chuỗi chứa dấu hai chấm
:mà không được đặt trong ngoặc kép - Ký tự tab lẫn vào phần thụt lề — YAML chỉ chấp nhận dấu cách
Ba bước để khắc phục:
- Đặt mọi giá trị chứa
:trong dấu ngoặc kép:msg: "Error: connection failed" - Thay thế toàn bộ tab bằng thụt lề 2 dấu cách
- Chạy
ansible-playbook --syntax-check playbook.ymlđể xác nhận
Lỗi đầy đủ
ERROR! We were unable to read either as JSON nor YAML, these are the errors we got from each:
JSON: Expecting value: line 1 column 1 (char 0)
YAML: mapping values are not allowed in this context
in "<unicode string>", line 12, column 18
Số dòng và số cột trong thông báo lỗi là manh mối nhanh nhất bạn có. Hãy nhảy thẳng đến đó trước tiên — đừng cuộn file và đoán mò.
Nguyên nhân gốc rễ
1. Dấu hai chấm không được đặt trong ngoặc kép trong giá trị chuỗi (phổ biến nhất)
YAML hiểu : là ký tự phân tách key-value. Nếu bạn để dấu hai chấm trong chuỗi mà không có ngoặc kép, trình phân tích sẽ đọc nó như một key mới — và mọi thứ phía sau sẽ bị hỏng.
# SAI — YAML hiểu "Error" là một key
- name: Show error
debug:
msg: Error: connection timed out
# ĐÚNG — đặt trong ngoặc kép
- name: Show error
debug:
msg: "Error: connection timed out"
URL cũng gặp vấn đề tương tự:
# SAI
url: https://example.com/api
# ĐÚNG
url: "https://example.com/api"
2. Lẫn lộn tab và dấu cách
YAML nghiêm cấm dùng tab để thụt lề. Chỉ cần một ký tự tab lạc vào — ví dụ khi dán code từ Slack hoặc PDF — là trình phân tích sẽ thất bại. Tệ hơn, nó thường chỉ sai số dòng.
# Hiển thị ký tự ẩn trong vim
:set list
# Hoặc dùng cat -A — tab hiển thị dạng ^I
cat -A playbook.yml | grep "\^I"
3. Mức thụt lề sai
Ansible yêu cầu thụt lề 2 dấu cách nhất quán xuyên suốt. Nếu bạn trộn lẫn block thụt lề 2 và 4 dấu cách trong cùng một file, lỗi này sẽ xuất hiện.
# SAI — thụt lề không đồng nhất
- name: Install nginx
apt:
name: nginx
state: present # thừa 2 dấu cách làm hỏng cấu trúc
# ĐÚNG
- name: Install nginx
apt:
name: nginx
state: present
4. Ký tự đặc biệt trong giá trị không được đặt trong ngoặc kép
Không chỉ dấu hai chấm. Bất kỳ ký tự nào sau đây đều có thể gây lỗi khi để trần: : { } [ ] , & * # ? | - < > = ! % @ \
# SAI
shell: echo hello && exit 0
# ĐÚNG — đặt trong ngoặc kép
shell: "echo hello && exit 0"
# Hoặc dùng literal block scalar
shell: |
echo hello && exit 0
Cách tìm và khắc phục vấn đề
Bước 1 — Chạy kiểm tra cú pháp trước
ansible-playbook --syntax-check playbook.yml
Lệnh này sẽ xuất ra số dòng chính xác. Hãy dùng nó. Đừng nhìn chằm chằm vào file và hy vọng tìm ra vấn đề.
Bước 2 — Lấy phản hồi chi tiết với yamllint
# Cài đặt
pip install yamllint
# Kiểm tra file
yamllint playbook.yml
# Cấu hình thân thiện với Ansible, nới lỏng giới hạn độ dài dòng
yamllint -d "{extends: default, rules: {line-length: {max: 120}}}" playbook.yml
Chỉ một lần chạy yamllint là có thể phát hiện tab, thụt lề sai và ký tự đặc biệt không được đặt trong ngoặc kép cùng một lúc. Nhanh hơn nhiều so với sửa từng lỗi một.
Bước 3 — Tìm và xóa tab
# Tìm tab — grep -Pn dùng Perl regex cho \t
grep -Pn "\t" playbook.yml
# Thay tab bằng 2 dấu cách trực tiếp trong file
sed -i 's/\t/ /g' playbook.yml
# Trong vim: chuyển tab thành dấu cách tự động
:set expandtab tabstop=2
:%retab
Bước 4 — Xác nhận đã sửa xong
ansible-playbook --syntax-check playbook.yml
# Kết quả sạch trông như thế này:
playbook: playbook.yml
Các mẫu phổ biến làm hỏng YAML
Mẫu 1 — Dấu hai chấm trong điều kiện when
# SAI — ": true" ở cuối không hợp lệ ở đây
when: ansible_os_family == "Debian": true
# ĐÚNG — điều kiện tự đánh giá là true
when: ansible_os_family == "Debian"
Mẫu 2 — Chuỗi nhiều dòng chứa dấu hai chấm
# SAI — dấu hai chấm ở dòng tiếp theo làm rối trình phân tích
msg: This is a message
with: a colon midway
# ĐÚNG — dùng literal block scalar
msg: |
This is a message
with: a colon midway
Mẫu 3 — Cú pháp sai trong bộ lọc default của Jinja2
# SAI — bộ lọc default không dùng dấu hai chấm
msg: "{{ my_var | default: 'fallback' }}"
# ĐÚNG — dùng = hoặc truyền giá trị như một đối số
msg: "{{ my_var | default('fallback') }}"
Mẹo hay
Khi debug một playbook phức tạp liên tục báo lỗi YAML, tôi hay dán đoạn code lỗi vào YAML ↔ JSON Converter trên ToolCraft. Công cụ này chuyển đổi YAML sang JSON theo thời gian thực, giúp bạn ngay lập tức thấy trình phân tích gặp lỗi ở đâu — không cần chạy Ansible nhiều lần. Mọi thứ đều xử lý trên trình duyệt, không có gì được tải lên.
Nó cũng hoạt động ngược lại: nếu ai đó gửi cho bạn một file cấu hình JSON và bạn cần đưa vào playbook, chuyển đổi sang YAML là xong — thụt lề đã đúng sẵn.
Phòng tránh
- Cài đặt editor: Đặt thụt lề là 2 dấu cách, bật "hiển thị ký tự ẩn" để phát hiện tab trước khi gây rắc rối, và bật hỗ trợ ngôn ngữ YAML
- VS Code: Cài extension "YAML" của Red Hat — nó kiểm tra playbook khi lưu và gạch chân các vấn đề ngay trong editor
- Thêm yamllint vào CI: Chỉ một dòng trong pipeline (
yamllint .) là đủ để phát hiện lỗi cú pháp trước khi Ansible chạy - Commit file cấu hình
.yamllintvào thư mục gốc của repo để mọi thành viên trong nhóm đều được kiểm tra theo cùng một bộ quy tắc
Tham khảo nhanh
# Luôn đặt trong ngoặc kép các mẫu sau:
msg: "Error: something failed" # dấu hai chấm trong giá trị
url: "https://example.com" # URL
cmd: "echo foo && bar" # ký tự shell đặc biệt
regexp: "^\\d+: " # regex có dấu hai chấm
# Dùng block scalar cho nội dung nhiều dòng:
script: |
#!/bin/bash
echo "Running: $1"
exit 0

