Lỗi Gặp Phải
Bạn chạy terraform plan hoặc terraform apply và gặp ngay lỗi này:
│ Error: Invalid combination of "count" and "for_each"
│
│ on main.tf line 3, in resource "aws_instance" "web":
│ 3: resource "aws_instance" "web" {
│
│ The "count" and "for_each" meta-arguments are mutually exclusive.
Một resource block (hoặc module block) đang có cả count lẫn for_each được định nghĩa cùng lúc. Terraform không thể xác định chiến lược lặp nào cần dùng, nên nó dừng lại ngay tại đó.
Nguyên Nhân
Cả count và for_each đều yêu cầu Terraform tạo nhiều instance của một resource — nhưng cách hoạt động của chúng hoàn toàn khác nhau:
count— tạo N bản sao, tham chiếu theo chỉ số (resource[0],resource[1], …)for_each— tạo một bản sao cho mỗi key trong map hoặc phần tử trong set, tham chiếu theo key (resource["web"],resource["db"], …)
Khai báo cả hai trong cùng một block là mâu thuẫn. Giống như bảo đầu bếp nấu một miếng bít tết vừa tái vừa chín hoàn toàn cùng lúc — chỉ được chọn một.
Ba tình huống thường gặp phải lỗi này:
- Đang chuyển code từ dạng
countsangfor_each, nhưng quên xóa dòngcountcũ - Copy-paste một resource block từ dự án khác đang dùng
count, rồi thêmfor_eachvào mà không dọn dẹp - Một module call nhận cả hai làm tham số từ các nguồn khác nhau
Cách Khắc Phục Từng Bước
Bước 1: Tìm block gây lỗi
Thông báo lỗi của Terraform bao gồm tên file và số dòng chính xác. Mở file đó và tìm block có cả hai tham số nằm cạnh nhau:
resource "aws_instance" "web" {
count = 3 # ← xóa một trong hai cái này
for_each = toset(["a", "b", "c"]) # ← chỉ giữ lại một
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
}
Bước 2: Chọn meta-argument phù hợp
Chọn cái thực sự phù hợp với trường hợp của bạn.
Dùng count khi bạn cần N bản sao giống nhau (hoặc gần giống nhau) và key không quan trọng:
resource "aws_instance" "web" {
count = 3
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
tags = {
Name = "web-${count.index}"
}
}
Dùng for_each khi mỗi instance có vai trò hoặc định danh riêng biệt — web, api, db — hoặc bạn cần tham chiếu chúng theo tên sau này:
locals {
instances = {
web = "t3.micro"
api = "t3.small"
db = "t3.medium"
}
}
resource "aws_instance" "servers" {
for_each = local.instances
ami = "ami-0c55b159cbfafe1f0"
instance_type = each.value
tags = {
Name = each.key
}
}
Tham chiếu đến một instance cụ thể sau này rất rõ ràng và dễ đọc:
output "web_ip" {
value = aws_instance.servers["web"].public_ip
}
Bước 3: Xóa meta-argument không dùng
Xóa cái bạn không giữ lại. Kiểm tra kỹ toàn bộ block — một dòng count = ... hay for_each = ... ẩn ở cuối cũng đủ gây ra lỗi. Mỗi resource chỉ nên có đúng một cái (hoặc không cái nào, nếu bạn chỉ cần một instance duy nhất).
Module block tuân theo quy tắc tương tự
Các lệnh gọi module cũng dễ mắc lỗi này:
# Sai
module "vpc" {
source = "./modules/vpc"
count = 2
for_each = toset(["us-east-1", "eu-west-1"])
}
# Đúng — chọn một trong hai:
module "vpc" {
source = "./modules/vpc"
for_each = toset(["us-east-1", "eu-west-1"])
region = each.value
}
Kiểm Tra Sau Khi Sửa
Chạy terraform validate trước — nhanh hơn plan đầy đủ và phát hiện lỗi cú pháp ngay lập tức:
terraform validate
Bạn sẽ thấy:
Success! The configuration is valid.
Sau đó xác nhận plan trông đúng không:
terraform plan
Một điều cần lưu ý: nếu bạn đang chuyển một resource đã có từ count sang for_each, Terraform sẽ lên kế hoạch xóa và tạo lại mọi instance. Định dạng key trong state thay đổi từ resource[0] sang resource["key"], và Terraform coi chúng là các đối tượng khác nhau. Dùng terraform state mv để migrate state thủ công nếu bạn cần tránh việc tạo lại resource.
Mẹo Nhanh
- Ưu tiên dùng
for_eachcho hầu hết hạ tầng thực tế. Xóa một phần tử khỏi danh sách dùngcountở giữa và Terraform sẽ dịch chuyển tất cả các chỉ số phía sau — có thể xóa và tạo lại những resource bạn chưa hề chỉnh sửa. Vớifor_each, chỉ key bị xóa là biến mất. - Map hoặc set rỗng vẫn hợp lệ —
for_each = {}tạo ra không resource nào mà không báo lỗi. - Không thể truyền danh sách thông thường vào
for_each— bọc nó bằngtoset():for_each = toset(var.names). Danh sách cho phép trùng lặp;for_eachthì không. - Dynamic block là chuyện khác — dùng
for_eachbên trong mộtdynamicblock trong một resource đã dùngcountlà hoàn toàn hợp lệ. Đó không phải xung đột mà Terraform đang phàn nàn.

